首页 > 解决方案 > MongoDB $set 合计

问题描述

我想根据另一个“源”集合的文档中的字段值,在“目标”集合的每个文档中设置一个新字段的值。

目标集合的文档如下所示:

数据库名称:

{ 
    "name" : "Larry", 
    "info" : {
        "phone" : "5551212"
    }
}
{ 
    "name" : "Curly", 
    "info" : {
        "phone" : "5551213"
    }
}
{ 
    "name" : "Moe", 
    "info" : {
        "phone" : "5551234"
    }
}

第二个集合的文档如下所示(我希望将此时区添加到目标集合中):

db.phones:

{ 
    "phone" : "5551212", 
    "timezone" : "UTC-6" 
}

{ 
    "phone" : "5551213", 
    "timezone" : "UTC-7" 
}

{ 
    "phone" : "5551234", 
    "timezone" : "UTC-6" 
}

我希望第一个“目的地”集合的文档最终看起来像这样:

数据库名称:

{ 
    "name" : "Larry", 
    "info" : {
        "phone" : "5551212",
        "timezone" : "UTC-6"
    }
}
{ 
    "name" : "Curly", 
    "info" : {
        "phone" : "5551213",
        "timezone" : "UTC-7"
    }
}
{ 
    "name" : "Moe", 
    "info" : {
        "phone" : "5551234",
        "timezone" : "UTC-6"
    }
}

换句话说,我有一个包含时区的非常大的集合(电话)和一个不包含时区的非常大的集合(名称),我希望第一个集合包含这些时区,并使用两者中的电话号码作为键。

我在 mongoShell 中尝试过,但没有成功:

list = db.names.aggregate([
    { $match: { } },

    { $lookup: {  
                from: "phones",
                localField: "info.phone",
                foreignField: "phone",
                as: "zoneinfo"
            }
    }
]);

list.result.forEach(function(x) {
    db.names.update({_id:x._id}, {$set:{'info.timezone':'zoneinfo.timezone'}});
});

因此,链接时区集合并将其添加到list结果中,作为每个文档的新字段(这很有效)。然后,由于我们无法在 中进行更新aggregate,因此迭代生成的文档,从之前操作中添加info.timezone的“临时”字段 中添加一个新的永久字段 。zoneinfo.timezone

我在这里做错了什么?还有其他更好的方法吗?每个集合中有数千个文档,因此手工工作是不可取的。

标签: mongodbaggregation-framework

解决方案


您需要记住的一件事是$lookup作为数组返回zoneInfo,因此为了使用该字段,您需要对其运行$unwind然后,您可以使用$addFields$project简单地重塑您的文档。尝试:

db.names.aggregate([
    {
        $lookup: {
            from: "phones",
            localField: "info.phone",
            foreignField: "phone",
            as: "phoneDetails"
        }
    },
    {
        $unwind: "$phoneDetails"
    },
    {
        $addFields: {
            "info.timezone": "$phoneDetails.timezone"
        }
    },
    {
        $project: {
            phoneDetails: 0
        }
    }
])

如果要更新现有集合,可以在最后一步添加$out 。


推荐阅读