【问题标题】:Can findOne match first or last?findOne 可以先匹配还是最后匹配?
【发布时间】:2014-09-07 16:31:14
【问题描述】:

我专门使用猫鼬,虽然我不认为这很重要。例如,假设我有一个名为 MongoQueue 的集合,我将一些人添加到该队列中。

`MongoQueue.save {function(err, firstPerson) {
   if (err) console.log(err);
   MongoQueue.save {function(err, secondPerson) {
      if (err) console.log(err);
      MongoQueue.save {function(err, thirdPerson) {
         if (err) console.log(err);
}}}`


如何检索第一次保存到 MongoQueue 的人?或者.... mongoDB 的 findOne() 方法如何缩小搜索范围?我可以指定 findOne() 的行为来选择集合中最旧的文档吗?或者我必须对集合进行排序(这将是最后的手段),如果是这样,我将如何按时间戳排序?

【问题讨论】:

  • MongoDB在DB对象_id中保存时间戳,自然是按日期排序

标签: javascript mongodb mongoose queue


【解决方案1】:

是的,您可以指定 .findOne() 的行为,这在本机驱动程序文档中得到了最佳展示。唯一的区别是,在 mongoose 实现中,“选项”文档必须是传递给方法的“第三个”参数。

因此,您可以为此提供“排序”规范,如可用选项中所示:

Queue.findOne({ },null,{ "sort": { "_id": -1 } },function(err,doc) {

您可以在 MongoDB shell 中使用$orderby 查询选项来执行此操作,以获取更多信息:

db.collection.findOne({ "$query": { }, "$orderby": { "_id": -1 } })

同样.findOne() 方法可能只返回一个文档,但它实际上只是.find() 的一个包装器,所以所有的修饰符都适用。包装只是在返回的游标上调用.next(),返回文档并丢弃游标。

这个更长的例子展示了不同的应用方式:

var async = require('async'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema;


mongoose.connect('mongodb://localhost/sequence');

var queueSchema = new Schema({
  name: String,
  same: { type: String, default: "same" }
});

var Queue = mongoose.model( "Queue", queueSchema );

var count = 0;

async.series(
  [

    // Remove any documents
    function(callback) {
      Queue.remove(function(err) {
        if (err) throw err;
        callback();
      });
    },

    // Insert some new ones
    function(callback) {
      async.eachSeries(
        ["one","two","three"],
        function(item,callback) {
          var queue = new Queue({ name: item });
          queue.save(function(err,doc) {
            if (err) throw err;
            console.dir(doc);
            callback(err,doc);
          });
        },
        function(err) {
          callback(err);
        }
      );
    },

    function(callback) {
      async.whilst(
        function() { return count < 2 },
        function(callback) {
          count++
          async.series(
            [
              // findOne is just the first one
              function(callback) {
                Queue.findOne({ "same": "same" },function(err,doc) {
                  if (err) throw err;
                  console.log( "FindOne:\n%s", doc );
                  callback();
                });
              },

              // Or is sorted
              function(callback) {
                Queue.findOne(
                  { "same": "same" },
                  null,
                  { "sort": { "_id": -1 } },
                  function(err,doc) {
                    if (err) throw err;
                    console.log("FindOne last:\n%s", doc );
                    callback();
                  }
                );
              },

              // find is ordered but not singular
              function(callback) {
                async.eachSeries(
                  ["first","last"],
                  function(label,callback) {
                    var direction = ( label == "first" ) ? 1 : -1;
                    var query = Queue.find({ "same": "same" })
                      .sort({ "_id": direction })
                      .limit(1);
                    query.exec(function(err,docs) {
                      if (err) throw err;
                      console.log( ".find() %s:\n%s", label, docs[0] );
                      callback();
                    });
                  },
                  function(err) {
                    callback();
                  }
                );
              },

              // findAndModify takes a sort
              function(callback) {
                Queue.findOneAndUpdate(
                  { "same": "same" },
                  { "$set": { "same": "different" } },
                  { "sort": { "_id": -1 } },
                  function(err,doc) {
                    if (err) throw err;
                    console.log( "findOneAndUpdate:\n%s", doc );
                    callback();
                  }
                );
              }

            ],function(err) {
              callback();
            }
          );
        },
        function(err) {
          callback();
        }
      );
    }
  ],function(err) {
    console.log("done");1
    mongoose.disconnect();
  }
);

【讨论】:

    【解决方案2】:

    findOne() 函数返回natural order 中的文档,这是磁盘上的顺序。您不能指望这会返回最近最少插入的文档。要返回最近最少插入的文档,您可以使用 find() 函数对 _id 进行反向排序,并且限制为 1,假设 _id 是为您生成的默认 ObjectId,或者在时间戳上(部分构建了 _id,来自时间戳,这就是它与 _id 一起使用的原因)。如果你使用 _id(它总是被索引)或索引时间戳字段,这将非常快。

    【讨论】:

    • 该命令不会以“自然”顺序返回,除非您实际告诉它不这样做。默认情况下使用_id 主索引,您可以提供排序规范。 finOne() 实际上只是 .find() 的一个包装器,它只返回一个文档。就像.find() 一样,还有其他方法可以提供排序和其他查询修饰符。
    • @NeilLunn:如果没有指定查询或排序选项,find()(或findOne())将使用自然顺序(而不是_id 索引)。另请参阅:What does Mongo sort on when no sort order is specified? .. 或尝试 .find.explain() 以确认正在使用 BasicCursor
    猜你喜欢
    • 2019-05-07
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    • 2011-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多