在你的问题中first_name
只能从Employees
收集和dep_name
只能从Departments
收藏。
您可以使用 MapReduce 和聚合框架来实现它。
1.MapReduce解决方案
如果你修改你的map和reduce函数如下
var mapD = function() {
for (var i=0; i<this.employees.length; i++)
emit(this.employees[i], { dep_id: this._id, dep_name: this.dep_name });
}
var mapE = function() { emit(this._id, { first_name: this.first_name }); }
var reduceLookUp = function(key, values) {
var results = {};
var departments = [];
values.forEach(function(value) {
var department = {};
if (value.dep_id !== undefined) department["dep_id"] = value.dep_id;
if (value.dep_name !== undefined) department["dep_name"] = value.dep_name;
if (Object.keys(department).length > 0) departments.push(department);
if (value.first_name !== undefined) results["first_name"] = value.first_name;
if (value.departments !== undefined) results["departments"] = value.departments;
});
if (Object.keys(departments).length > 0) results["departments"] = departments;
return results;
}
然后首先调用 MapReduce
db.Departments.mapReduce(mapD, reduceLookUp, { out: { reduce: "joined" } });
将插入到joined
收藏
{
"_id" : "1234",
"value" :
{
"departments" :
[
{ "dep_id" : "d001", "dep_name" : "Sales" },
{ "dep_id" : "d004", "dep_name" : "Quality M" }
]
}
}
当第二次通话时
db.Employees.mapReduce(mapE, reduceLookUp, { out: { reduce: "joined" } });
应该插入
{ "_id" : "1234", "value" : { "first_name" : "John" } }
但是,根据文档 https://docs.mongodb.com/manual/reference/command/mapReduce/#out-options, reduce
输出选项将
如果输出集合,则将新结果与现有结果合并
已经存在。如果现有文档与新文档具有相同的密钥
结果,将reduce函数应用于新的和现有的
文档并用结果覆盖现有文档
因此,在您的情况下,将使用参数再次调用reduce函数
key = "1234",
values =
[
{
"departments" :
[
{ "dep_id" : "d001", "dep_name" : "Sales" },
{ "dep_id" : "d004", "dep_name" : "Quality M" }
]
},
{ "first_name" : "John" }
]
最终结果是
{
"_id" : "1234",
"value" :
{
"first_name" : "John",
"departments" :
[
{ "dep_id" : "d001", "dep_name" : "Sales" },
{ "dep_id" : "d004", "dep_name" : "Quality M" }
]
}
}
2.聚合框架方案
解决您问题的更好方法是使用聚合框架 https://docs.mongodb.com/manual/aggregation/而不是 Map-Reduce。在这里你会使用$lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/从中获取一些数据的阶段Employees
db.Departments.aggregate([
{ $unwind: "$employees" },
{
$lookup:
{
from: "Employees",
localField: "employees",
foreignField: "_id",
as: "employee"
}
},
{ $unwind: "$employee" },
{
$group:
{
"_id": "$employees",
"first_name": { $first: "$employee.first_name" },
"departments": { $push: { dep_id: "$_id", dep_name: "$dep_name" } }
}
}
]);
这将导致
{
"_id" : "1234",
"first_name" : "John",
"departments" :
[
{ "dep_id" : "d001", "dep_name" : "Sales" },
{ "dep_id" : "d004", "dep_name" : "Quality M" }
]
}