我怎么能更新数组中的特定重复项

时间:2015-06-07 02:03:36

标签: mongodb mongodb-query pymongo

我想将原始文档更新为预期文档

即删除重复的连续相同价格记录,

只保留最后一个。

如何使用mongo查询?

预期文件

{
  "_id": "2015-06-12-TPE-KIX",
  "flight_date": new Date("2015-06-12T08:00:00+0800"),
  "history": [
    {
      "updated_at": new Date(1433515526965),
      "price": 6740
    },
    {
      "updated_at": new Date(1433607771762),
      "price": 5490
    }
  ]
}

原始文件

{
  "_id": "2015-06-12-TPE-KIX",
  "flight_date": new Date("2015-06-12T08:00:00+0800"),
  "history": [
    {
      "updated_at": new Date(1433492046834),
      "price": 6740
    },
    {
      "updated_at": new Date(1433492048208),
      "price": 6740
    },
    {
      "updated_at": new Date(1433492428642),
      "price": 6740
    },
    {
      "updated_at": new Date(1433492430039),
      "price": 6740
    },
    {
      "updated_at": new Date(1433515526965),
      "price": 6740
    },
    {
      "updated_at": new Date(1433562561356),
      "price": 5490
    },
    {
      "updated_at": new Date(1433603772299),
      "price": 5490
    },
    {
      "updated_at": new Date(1433607771762),
      "price": 5490
    }
  ]
}

1 个答案:

答案 0 :(得分:1)

您可以使用聚合框架作为将数组减少到所需项目的方法,然后使用结果更新集合中的每个文档。仅限Shell示例,但适用相同的基本逻辑:

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

db.collection.aggregate([
    // Unwind the array
    { "$unwind": "$history" },

    // Group by price on each document
    { "$group": {
        "_id": { 
            "_id": "$_id",
            "flight_date": "$flight_date",
            "price": "$history.price"
        },
        "updated_at": { "$max": "$history.updated_at" }
    }},

    // Sort by updated_at in each document
    { "$sort": { "_id._id": 1, "updated_at": 1 } },

    // Group back per document
    { "$group": {
        "_id": "$_id._id",
        "flight_date": { "$first": "$_id.flight_date" },
        "history": {
            "$push": {
                "updated_at": "$updated_at",
                "price": "$_id.price"
            }
        }
    }}
]).forEach(function(doc) {
    bulk.find({ "_id": doc._id }).updateOne({
        "$set": { "history": doc.history }
    });
    count++;

    // Send to server every 1000 and re-init
    if ( count % 1000 == 0 ) {
        bulk.execute();
        bulk = db.collection.initializeOrderedBulkOp();
    }
});

// Process any queued 
if ( count % 1000 != 0 )
    bulk.execute();

这样可以将结果中的数组减少到你想要的结果:

{
    "_id" : "2015-06-12-TPE-KIX",
    "flight_date" : ISODate("2015-06-12T00:00:00Z"),
    "history" : [
            {
                    "updated_at" : ISODate("2015-06-05T14:45:26.965Z"),
                    "price" : 6740
            },
            {
                    "updated_at" : ISODate("2015-06-06T16:22:51.762Z"),
                    "price" : 5490
            }
    ]
}

但是如果您实际上正在更新文档,我会按照游标读取的每个文档的代码进行数组缩减,然后按文档发送类似的批量更新请求。

$unwind操作对文档集合有很大的开销,并且由于您实际上没有跨文档“聚合”,因此在客户端代码中操作数组的方法将是最有效的方法。

当然,如果您可以使用新的集合或者很乐意重命名集合,那么请使用$out选项和聚合,如上所示。