将两个字段合并为 object

merge two fields into an object

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

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

现在,我想将 PhoneEmail 合并为 contact 并更新此 collection

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" }

有人可以帮我解决这个问题吗?

这有点过分了。下面是一个更简单的管道:

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

要使用新架构更新 table,您需要利用 bulkWrite() API which is more efficient for the task. Consider the following bulk update operation where you just iterate using the 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 个文档只发送一次请求来处理。