将两个字段合并为一个对象

时间:2016-09-28 13:05:52

标签: mongodb mongodb-query aggregation-framework mongodb-aggregation

我正在尝试合并两个字段 这是我的收藏

db.Acc_Details.findOne()
{ 
    "_id": ObjectId("577f43fe748646cc91370713"), 
    "Acc_Id": 1, 
    "Name": "xxxxx", 
    "Phone": NumberLong("123456789"), 
    "Email": "xxxxxx@gmail.com" 
}

现在,我想将PhoneEmail合并到contact并更新此集合

db.Acc_Details.findOne()
{ 
    "_id": ObjectId("577f43fe748646cc91370713"), 
    "Acc_Id": 1, 
    "Name": "xxxxx", 
    "Contact": {
        "Phone": NumberLong("123456789"), 
        "Email": "xxxxxx@gmail.com"
    } 
}

这是我尝试的但我不知道它是否正确:

db.Acc_Details.aggregate([
    {
        $project: {
            "Contact": {
                "$map": {
                    input: { $literal: ["p1", "p2"] },
                    as: "p",
                    in: {
                        $cond: [
                           { $eq: ["$$p", "p1"] },
                           "$Phone",
                           "$Email"
                        ]
                    }
                }
            }
        }
    },
    { $unwind: "$Contact" }
])

结果是

{ "_id" : ObjectId("577f43fe748646cc91370713"), "Contact" : NumberLong("12356789") }
{ "_id" : ObjectId("577f43fe748646cc91370713"), "Contact" : "xxxxxx@gmail.com" }

有人可以帮我这个吗?

1 个答案:

答案 0 :(得分:2)

这有点矫枉过正。下面是一个更简单的管道:

db.Acc_Details.aggregate([
    {
        "$project": {
            "Acc_Id": 1, 
            "Name": 1, 
            "Contact": {
                "Phone": "$Phone", 
                "Email": "$Email"
            } 
        }
    }
])

要使用新架构更新表,您需要利用bulkWrite() API利用更新,这对于任务更有效。考虑以下批量更新操作,您只需使用 find() 光标进行迭代,并将字段更新为:

var ops = [];
db.Acc_Details.find().snapshot().forEach(function(doc) {
    ops.push({
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": {
                "$set": { 
                    "Contact": { "Phone": doc.Phone, "Email": doc.Email }
                },
                "$unset": { "Phone": "", "Email": "" }
            }
        }
    });

    if (ops.length === 500) {
        db.Acc_Details.bulkWrite(ops);
        ops = [];
    }
})

if (ops.length > 0)  db.Acc_Details.bulkWrite(ops);

或使用上述汇总结果:

var ops = [];
db.Acc_Details.aggregate([
    {
        "$project": {
            "Contact": {
                "Phone": "$Phone", 
                "Email": "$Email"
            } 
        }
    }
]).forEach(function(doc) {
    ops.push({
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": {
                "$set": { "Contact": doc.Contact },
                "$unset": { "Phone": "", "Email": "" }
            }
        }
    });

    if (ops.length === 500) {
        db.Acc_Details.bulkWrite(ops);
        ops = [];
    }
})

if (ops.length > 0)  db.Acc_Details.bulkWrite(ops);

或者对于MongoDB 2.6.x和3.0.x版本,请使用此版本的 Bulk 操作:

var bulk = db.Acc_Details.initializeUnorderedBulkOp(),
    counter = 0;
db.Acc_Details.find().snapshot().forEach(function(doc) {
    bulk.find({ "_id": doc._id }).updateOne({
        "$set": { 
            "Contact": { "Phone": doc.Phone, "Email": doc.Email }
        },
        "$unset": { "Phone": "", "Email": "" }
    });

    if (counter % 500 === 0) {
        bulk.execute();
        bulk = db.Acc_Details.initializeUnorderedBulkOp();
    }
});

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

这两种情况下的批量操作API都有助于减少服务器上的IO负载,方法是在集合中每500个文档中只发送一次请求进行处理。