簡體   English   中英

Mongodb:匯總子文檔數組上的值

[英]Mongodb: aggregate values on array of subdocuments

我有文件收集:

{
    "_id": ObjectId("55dc62647cda24224372e308"),
    "last_modified": ISODate("2015-07-01T15:57:26.874Z"),
    "services": [
        {"last_modified": ISODate("2015-05-08T07:10:11.250Z")},
        {...}
    ]
}

我需要通過查找其服務的最大last_updated值來刷新文檔的last_modified字段:

>db.documents.find().map(function(d){
    db.documents.update(
        {_id: d._id},
        {$set: {last_updated: Math.max(d.services.last_updated)}}
    )
})
Tue Aug 25 16:01:20.536 TypeError: Cannot read property 'last_modified' of undefined

如何訪問和聚合數組中子文檔的屬性?

這里的基本過程是,您需要從數組中獲取最大排序日期,並從中獲取值。 當然,您需要一個循環,並且不能直接在更新語句中訪問文檔的值。 因此,您需要先閱讀它,但是批量操作在這里有幫助:

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

db.documents.find().forEach(function(doc) {
  var last_modified = doc.services.sort(function(a,b) {
    return a.last_modified < b.last_modified;
  }).slice(-1)[0].last_modified;

  bulk.find({ "_id": doc._id }).updateOne({
    "$set": { "last_modified": last_modified }
  });
  count++;

  if ( count % 1000 == 0 ) {
    bulk.execute();
    bulk = db.documents.initializeOrderedBulkOp();
  }

});

if ( count % 1000 != 0 )
  bulk.execute();

更好的是,考慮在添加新項目時對數組本身進行排序。 這基本上是通過$push$sort修飾符完成的

 db.documents.update(
     { "_id": id },
     { "$push": { 
         "services": {
             "$each": [{ "last_modified": date }],
             "$sort": { "last_modified": 1 }
     }}
)

甚至會忘記$sort因為無論如何所有數組值都附加到末尾,除非您另行告知操作。

然后,您基本上可以使用$slice縮短此過程。

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

db.documents.find(
    {},
    { 
        "last_modified": { "$slice": -1}
    }
).forEach(function(doc) {

  bulk.find({ "_id": doc._id }).updateOne({
    "$set": { "last_modified": doc.last_modified[0] }
  });
  count++;

  if ( count % 1000 == 0 ) {
    bulk.execute();
    bulk = db.documents.initializeOrderedBulkOp();
  }

});

if ( count % 1000 != 0 )
  bulk.execute();

可以在此處使用聚合框架,但實際上考慮到僅從每個文檔的對象中獲取最大日期值是多么簡單,實際上並沒有必要。

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

db.documents.aggregate([
    { "$unwind": "$services" },
    { "$group": {
        "_id": "$_id",
        "last_modified": { "$max": "$services.last_modified" }
    }}
]).forEach(function(doc) {

  bulk.find({ "_id": doc._id }).updateOne({
    "$set": { "last_modified": doc.last_modified }
  });
  count++;

  if ( count % 1000 == 0 ) {
    bulk.execute();
    bulk = db.documents.initializeOrderedBulkOp();
  }

});

if ( count % 1000 != 0 )
  bulk.execute();

而且由於使用$unwind因此實際上付出的成本比必要的多得多。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM