如何删除重复的嵌入文档

how to drop duplicate embedded document

我有包含许多子文档列表的用户集合。架构是这样的:

   {
    _id: ObjectId(),
    name: aaa,
    age: 20,
    transactions:[
        {
         trans_id: 1,
         product: mobile,
         price: 30,
        },
        {
         trans_id: 2,
         product: tv,
         price: 10
        },
        ...]
    ...
   }

所以我有一个疑问。 transactions 列表中的 trans_id 在所有产品中都是唯一的,但我可能已经用相同的 trans_id 再次复制了相同的交易(由于错误的 ETL 编程)。现在我想删除那些重复的子文档。我索引了 trans_id 以为没有 unique。我读到了 dropDups 选项。但是它会删除数据库中存在的特定重复项还是会删除整个文档(我绝对不想要)。如果不行怎么办?

PS: 我正在使用 MongoDB 2.6.6 版本。

我们在这里看到的最接近的情况是,现在您需要一种方法来定义数组中的 "distinct" 项,其中某些项实际上是数组中其他项的 "exact copy"数组。

最好的情况是使用 $addToSet along with the $each modifier within a looping operation for the collection. Ideally you use the Bulk Operations API 以利用减少的流量:

var bulk = db.collection.initializeOrderedBulkOperation();
var count = 0;

// Read the docs
db.collection.find({}).forEach(function(doc) {
    // Blank the array
    bulk.find({ "_id": doc.id })
        .updateOne({ "$set": { "transactions": [] } });
    // Resend as a "set"
    bulk.find({ "_id": doc.id })
        .updateOne({ 
            "$addToSet": { 
                "trasactions": { "$each": doc.transactions }
            }
        });
    count++;

    // Execute once every 500 statements ( actually 1000 )
    if ( count % 500 == 0 ) {
        bulk.execute()
        bulk = db.collection.initializeOrderedBulkOperation();
    }
});

// If a remainder then execute the remaining stack
if ( count % 500 != 0 )
    bulk.execute();

所以只要 "duplicate" 的内容是 "entirely the same" 那么这个方法就有效。如果实际上 "duplicated" 的唯一内容是 "trans_id" 字段,那么您需要一种完全不同的方法,因为 "whole documents" 的 none 是 "duplicated",这意味着你需要更多的逻辑来做到这一点。