在mongo中插入数组大小的字段

时间:2015-10-27 17:42:26

标签: mongodb mongodb-query aggregation-framework

我在mongodb中有一个文件,包含一些数组。现在我需要一个包含此数组项目数量的字段。所以我需要更新添加此字段的文档。 我只是认为这会奏效:

db.myDocument.update({
     "itemsTotal": {
         $exists: false
     },
     "items": {
         $exists: true
     }
 }, {
     $set: {
         itemsTotal: {
             $size: "$items"
         }
     }
 }, {
 multi: true
 })

但它完成了"而不是okForStorage"。 我也尝试进行聚合,但它会抛出异常:

"errmsg" : "exception: invalid operator '$size'",
"code" : 15999,
"ok" : 0

什么是最佳解决方案,我做错了什么?我开始考虑编写用于计算总计的Java工具并用它来更新文档。

3 个答案:

答案 0 :(得分:1)

您可以初始化 Bulk() 操作构建器,以循环更新文档,如下所示:

var bulk = db.collection.initializeOrderedBulkOp(),   
    count = 0;

db.collection.find("itemsTotal": { "$exists": false },
     "items": {
         $exists: true
     }
).forEach(function(doc) { 
    var items_size = doc.items.length;
    bulk.find({ "_id": doc._id }).updateOne({ 
        "$set": { "itemsTotal": items_size }
    });
    count++;
    if (count % 100 == 0) {
        bulk.execute();
        bulk = db.collection.initializeUnorderedBulkOp();
    }
});

if (count % 100 != 0) { bulk.execute(); }

答案 1 :(得分:1)

您可以使用.aggregate()方法$project文档并返回items数组的$size。之后,您需要使用.forEach循环和$set文档的itemTotal字段使用"Bulk"操作循环遍历汇总结果,以获得最高效率。

var bulkOp = db.myDocument.initializeUnorderedBulkOp(); 
var count = 0;

db.myDocument.aggregate([
    { "$match": { 
        "itemsTotal": { "$exists": false } ,
        "items": { "$exists": true }
    }}, 
    { "$project": { "itemsTotal": { "$size": "$items" } } }
]).forEach(function(doc) { 
        bulkOp.find({ "_id": doc._id }).updateOne({ 
            "$set": { "itemsTotal": doc.itemsTotal }
        });
        count++;
        if (count % 200 === 0) {
            // Execute per 200 operations and re-init
            bulkOp.execute();
            bulkOp = db.myDocument.initializeUnorderedBulkOp();
        }
})

// Clean up queues
if (count > 0) { 
    bulkOp.execute();
}

答案 2 :(得分:1)

从MongoDB v3.4开始更容易,该版本引入了$addFields聚合管道运算符。我们还将使用$out运算符将聚合结果输出到同一集合(replacing the existing collection is atomic)。

db.myDocuments.aggregate( [
  {
    $addFields: {
      itemsTotal: { $size: "$items" } ,
    },
  },
  {
    $out: "myDocuments"
  }
] )

警告:此解决方案要求所有文档具有items字段。如果某些文档没有此文档,aggregate将失败并

  

“ $ size的参数必须为数组,但类型为:缺少”

您可能会认为可以向聚合中添加$match来仅过滤包含items的文档,但这意味着所有包含items的文档都不会被输出回myDocuments集合,这样您将永久丢失它们。