在对象数组中查找,就像在单独的集合中查找一样

Find in array of objects as in a separate collection

本文关键字:查找 一样 集合 数组 对象 单独      更新时间:2023-09-26

短问题:

如果log是一个对象数组来做这样的事情(在mongo shell或nodejs或meteor minimongo,任何东西),是否有任何解决方案?

    var log = db.getCollection('myCollection').findOne({_id: 'someId'}).log
    var collection = useAsCollection(log);
    collection.find(anyValidMongoSelector);

长问题:

我有一个像这样的文档:

    {
      "_id": "someId",
      "log": [{
        "operation": "trade",
        "date": ISODate("2010-11-12T17:59:04.332+03:00")
      }, {
        "operation": "sell",
        "date": ISODate("2011-11-14T08:53:22.937+03:00")
      }, {
        "operation": "buy",
        "date": ISODate("2014-11-14T12:44:37.202+03:00")
      }, {
        "operation": "sell",
        "date": ISODate("2012-11-15T12:32:40.910+03:00")
      }, {
        "operation": "buy",
        "date": ISODate("2013-11-17T17:43:15.705+03:00")
      }, {
        "operation": "trade",
        "date": ISODate("2018-11-18T08:51:42.518+03:00")
      }]
    }

我经常需要知道一些与log数组相关的具体信息。例如,最早的操作

如果数组本身是一个集合,我只做一个搜索:

    db.getCollection('log').find().sort({date: 1})

但是这样的搜索不能在我的情况下进行。我知道,有$elemMatch投影,但它只返回符合条件的第一个元素,并且有一些其他限制。

我的解决方案是在myscript.js中写下一些代码:

    function getEarlier() {
      var h1 = db.getCollection('myCollection').findOne({_id: 'someId'}).log,
          earliestDate = new Date();
      for (var i in h1) {
        if (h1[i].date < earliestDate) {
          earliestDate = h1[i].date;}}
      print('The earliest document: ' + earliestDate);}
    getEarlier();
然后执行
    mongo myDB myscript.js

实际的文档结构更复杂,也站在我面前的问题,所以我有很多这样的函数迭代这个文档。

再来一遍这个问题。是否有任何解决方案从盒子做这样的事情(在mongo shell或nodejs或meteor minimongo,任何东西)?

    var log = db.getCollection('myCollection').findOne({_id: 'someId'}).log
    var collection = useAsCollection(log);
    collection.find().sort({date: 1})

我有一个项目micromongo,它允许在JSON对象数组上执行Mongodb查询的一些有限子集。

游标目前不支持,但对于您的情况,您可以执行以下操作:

var mm = require('micromongo');
function ISODate(s) { return new Date(s); }
var log = [{
  "operation": "trade",
  "date": ISODate("2010-11-12T17:59:04.332+03:00")
}, {
  "operation": "sell",
  "date": ISODate("2011-11-14T08:53:22.937+03:00")
// ......
}];
var sorted = mm.aggregate(log, [
  { $sort: { date: 1 } }
]);
console.log(sorted);

甚至:

var sorted = mm.aggregate(log, [
  { $sort: { date: 1 } },
  { $limit: 1 }
]);

…如果您只需要获取一个最新值;

如果使用Mongodb本地驱动程序,您的问题的解决方案可能如下所示:

var mm = require('micromongo');
var MongoClient = require('mongodb').MongoClient;    
var url = 'mongodb://localhost:27017/test';
MongoClient.connect(url, function(err, db) {
  console.log("Connected succesfully to server");
  db.collection('logger').findOne({}, function(err, doc) {
    var log = doc.log;
    var sorted = mm.aggregate(log, [
      { $sort: { date: -1 } }
    ]);
    console.log(sorted);
    db.close()
  });
});

请注意,它使用未排序的未索引数据,但我假设log数组相对较小,否则您将把它放在单独的集合中。

您更新它并在写而不是读时进行切片。

Logs.update({
  _id: 'someid'
}, {
  $push: {
    'log': {
      $each: [{
        operation: 'sell',
        timestamp: new Date
      }],
      $slice: -100,
      $sort: { timestamp: 1 }
    }
  }
});

本质上,这个使数组保持有序,而不是对它进行查询并保持有序。

我在我自己的项目中做了类似的事情,我异步更新日志。