【问题标题】:Query arrays within array in MongoDB; update if exists, insert if empty查询MongoDB中数组内的数组;如果存在则更新,如果为空则插入
【发布时间】:2014-03-26 16:39:20
【问题描述】:

我想更改 MongoDB 中的文档。以下是相关文档结构的示例摘录:

{ values : { M1 : [[1395964800, 0.083434], ... , [1395964860, 0.043424]] } }

首先,键M1 包含一个数组数组。我必须搜索嵌套数组中的[0] 项(纪元时间,例如1395964800, 1395964860)。如何通过[0] 嵌套数组值查找文档?例如,我尝试过搜索:

db.myCollection.find({ "values" : { "M1" : [1395964800, 0.083434] } }).limit(1);

诚然,我预计这种方法会同时通过 [0] 嵌套数组值和[1] 嵌套数组值进行搜索。即使这样,这也不起作用,并且不返回任何结果(但不会出错)。

其次,如果这个 [0] 数组值已经存在(纪元时间),我想更新/覆盖该嵌套数组中的 [1] 元素(数据值)。如果 [0] 数组值在 M1 数组中不存在,我想将它(以及随附的数据值)添加到 M1 数组中。

我希望我会使用类似的东西:

db.collection("myCollection").findAndModify(
   { ........ }, // query
   { }, // sort
   { $set : { ... : ... }}, // set
   { upsert: true }, // insert if does not exist
   function (err, result) {
      (err) throw err
   }
);

问题

  1. 如何按照描述进行搜索
  2. 如何按照说明进行更新

【问题讨论】:

    标签: javascript mongodb


    【解决方案1】:

    以下代码是我为解决我的问题而创建的解决方案。特别是,以下线程帮助了我:

    需要明确的是,在我的情况下,unixTime 值在数组本身和嵌套数组中都是唯一的。我希望其他人会觉得这很有帮助。

    var unixTime = 1395964800; // e.g. This can be programmatically changed
    var _query = {'values.M1' : { '$elemMatch' : { '$in' : [unixTime] } } } ; // This allows us to search within the nested arrays for a specific value (in any position).
    
    db.collection("myCollection").findAndModify(
        _query, // query
        { start_timestamp : -1 }, // sort
        { $set : { 'values.M1.$' : [unixTime, value] }}, // set with $, which is crucual because it uses the previously found/matched array item
        { upsert: true}, // insert if does not exist
        function (err, result) {
            if (err) console.log(error);
            console.log('results',results);
        }
    );
    

    【讨论】:

      【解决方案2】:

      这里有匿名嵌套数组,这对于处理 MongoDB 中的数据不是很好的格式。除了选择问题之外,匹配要更新的项目是一个真正的问题,因为您在尝试时仅限于 first 索引匹配 *实际匹配一个位置。

      请参阅positional $ 操作员文档。

      要解决这个问题,您实际上需要一个适合的架构,例如:

      { 
          values : { 
              M1 : [
                  { "time": 1395964800, "value": 0.083434 },
                  { "time": 1395964860, "value": 0.043424 } 
              ]
          }
      }
      

      使用该结构,您可以像这样搜索“时间”值:

      db.collection.find(
          { "values.M1.time": 1395964860 },
          { "values.M1.$": 1 }
      )
      

      这会将数组的“匹配”元素投影到找到它的文档中。

      对于更新,您可以使用位置运算符:

      db.collection.update(
         { "values.M1.time": 1395964860 },
         { "$set": { "values.M1.$.value": 0.055000 } }
      )
      

      但是对于当前的嵌套形式,你没有比显式匹配更好的了:

      db.collection.find({ "values.M1.0.0": 1395964800 })
      

      而且您需要知道您尝试匹配的索引值,这违背了存储它的目的。

      更改您的架构,这将是一个更加灵活的解决方案。

      【讨论】:

      • 感谢尼尔的详细回复。我很乐意按时显式匹配,但我不一定知道该条目存在,我当然也不知道附带的值。我已经发布了一个解决方案,解决了最初问题中的两点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-17
      相关资源
      最近更新 更多