MongoDB$集合在一起

MongoDB$集合在一起,mongodb,aggregation-framework,Mongodb,Aggregation Framework,我想根据另一个“源”集合的文档中的字段值,在“目标”集合的每个文档中设置一个新字段的值 目标集合的文档如下所示: db.name: { "name" : "Larry", "info" : { "phone" : "5551212" } } { "name" : "Curly", "info" : { "phone" : "5551213" } } { "name" : "Moe", "i

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

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

db.name:

{ 
    "name" : "Larry", 
    "info" : {
        "phone" : "5551212"
    }
}
{ 
    "name" : "Curly", 
    "info" : {
        "phone" : "5551213"
    }
}
{ 
    "name" : "Moe", 
    "info" : {
        "phone" : "5551234"
    }
}
{ 
    "name" : "Larry", 
    "info" : {
        "phone" : "5551212",
        "timezone" : "UTC-6"
    }
}
{ 
    "name" : "Curly", 
    "info" : {
        "phone" : "5551213",
        "timezone" : "UTC-7"
    }
}
{ 
    "name" : "Moe", 
    "info" : {
        "phone" : "5551234",
        "timezone" : "UTC-6"
    }
}
第二个集合的文档如下所示(我希望将此时区添加到目标集合):

db.phones:

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

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

{ 
    "phone" : "5551234", 
    "timezone" : "UTC-6" 
}
我希望第一个“目的地”集合的文档最终看起来像这样:

db.name:

{ 
    "name" : "Larry", 
    "info" : {
        "phone" : "5551212"
    }
}
{ 
    "name" : "Curly", 
    "info" : {
        "phone" : "5551213"
    }
}
{ 
    "name" : "Moe", 
    "info" : {
        "phone" : "5551234"
    }
}
{ 
    "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'}});
});
因此,将时区集合链接起来,并将其添加到
列表
,作为每个文档上的一个新字段(这非常有效)。然后,由于我们无法在
聚合中执行更新,因此迭代生成的文档,从先前操作中添加的“临时”字段
zoneinfo.timezone
添加一个新的永久字段
info.timezone


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

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


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

由于OP包含一个匹配管道(尽管是空管道),因此可能需要警告使用$out将现有集合的内容替换为聚合结果。因此,如果曾经修改匹配管道以对子集执行聚合,那么那些未包含在匹配中的文档将从现有集合中删除,而不是简单地保持“未修改”@JerrenSaunders我想他是在试图修改整个收藏,因为这个匹配是空的,但你提到:$out总是替换现有的收藏,这很好,谢谢you@JerrenSaunders抢手货是的,源集合和目标集合中的某些文档中没有电话号码,这意味着上述操作的结果文档是原始集合的子集。我不能简单地使用$out删除目标集合中的现有记录。这就是我开始使用两步update()方法的原因,也是为什么我有一个空白的$match查询:我删除了实际的条件以简化我的问题。我的$match是:{'info.phone':{$exists:1}},只复制提供电话号码的联系人的时区信息。@JohnMarquez您是否考虑过使用
preserveNullAndEmptyArrays:true
选项$unwind?这将使这些文档保留一个
info.phone