Vzq*_*van 3 lookup join mapreduce mongodb nosql
我已经知道MongoDB不支持连接操作,但我必须$lookup
使用mapReduce
范例模拟(来自聚合框架).
我的两个系列是:
// Employees sample
{
"_id" : "1234",
"first_name" : "John",
"last_name" : "Bush",
"departments" :
[
{ "dep_id" : "d001", "hire_date" : "date001" },
{ "dep_id" : "d004", "hire_date" : "date004" }
]
}
{
"_id" : "5678",
"first_name" : "Johny",
"last_name" : "Cash",
"departments" : [ { "dep_id" : "d001", "hire_date" : "date03" } ]
}
{
"_id" : "9012",
"first_name" : "Susan",
"last_name" : "Bowdy",
"departments" : [ { "dep_id" : "d004", "hire_date" : "date04" } ]
}
// Departments sample
{
"_id" : "d001",
"dep_name" : "Sales",
"employees" : [ "1234", "5678" ]
},
{
"_id" : "d004",
"name" : "Quality M",
"employees" : [ "1234", "9012" ]
}
Run Code Online (Sandbox Code Playgroud)
实际上我想得到这样的结果:
{
"_id" : "1234",
"value" :
{
"first_name" : "John",
"departments" :
[
{ "dep_id" : "d001", "dep_name" : "Sales" },
{ "dep_id" : "d004", "dep_name" : "Quality M" }
]
}
}
{
"_id" : "5678",
"value" :
{
"first_name" : "Johnny",
"departments" : [ { "dep_id" : "d001", "dep_name" : "Sales" } ]
}
}
{
"_id" : "9012",
"value" :
{
"first_name" : "Susan",
"departments" : [ { "dep_id" : "d004", "dep_name" : "Quality M" } ]
}
}
Run Code Online (Sandbox Code Playgroud)
共同领域是dep_id
(来自员工)和_id
(来自部门).
我的代码是下一个,但它不能正常工作.
var mapD = function() {
for (var i=0; i<this.employees.length; i++) {
emit(this.employees[i], { dep_id: 0, dep_name: this.dep_name });
}
}
var mapE = function() {
for (var i=0; i<this.departments.length; i++) {
emit(this._id, { dep_id: this.departments[i].dep_id, dep_name: 0 });
}
}
var reduceLookUp = function(key, values) {
var result = {dep_id: 0, dep_name: 0};
values.forEach(function(value) {
if (value.dep_name !== null && value.dep_name !== undefined) {
result.dep_name = values.dep_name;
}
if (value.dep_id !== null && value.dep_id !== undefined) {
result.dep_id = value.dep_id;
}
});
return result;
};
db.Departments.mapReduce(mapD, reduceLookUp, { out: { reduce: "joined" } });
db.Employees.mapReduce(mapE, reduceLookUp, { out: { reduce: "joined" } });
Run Code Online (Sandbox Code Playgroud)
我真的很感激你的帮助!提前致谢.
在您的问题first_name
中,只能从Employees
集合中获取,并且只能从集合dep_name
中获取Departments
.
您可以使用MapReduce和聚合框架来实现它.
1. MapReduce解决方案
如果您修改地图并减少功能如下
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;
}
Run Code Online (Sandbox Code Playgroud)
然后第一次MapReduce调用
db.Departments.mapReduce(mapD, reduceLookUp, { out: { reduce: "joined" } });
Run Code Online (Sandbox Code Playgroud)
将插入到joined
集合中
{
"_id" : "1234",
"value" :
{
"departments" :
[
{ "dep_id" : "d001", "dep_name" : "Sales" },
{ "dep_id" : "d004", "dep_name" : "Quality M" }
]
}
}
Run Code Online (Sandbox Code Playgroud)
第二次通话
db.Employees.mapReduce(mapE, reduceLookUp, { out: { reduce: "joined" } });
Run Code Online (Sandbox Code Playgroud)
应插入
{ "_id" : "1234", "value" : { "first_name" : "John" } }
Run Code Online (Sandbox Code Playgroud)
但是,根据文档,reduce
输出选项将
如果输出集合已存在,则将新结果与现有结果合并.如果现有文档与新结果具有相同的密钥,请将reduce函数应用于新文档和现有文档,并使用结果覆盖现有文档
因此,在您的情况下,将使用参数再次调用reduce函数
key = "1234",
values =
[
{
"departments" :
[
{ "dep_id" : "d001", "dep_name" : "Sales" },
{ "dep_id" : "d004", "dep_name" : "Quality M" }
]
},
{ "first_name" : "John" }
]
Run Code Online (Sandbox Code Playgroud)
最后的结果是
{
"_id" : "1234",
"value" :
{
"first_name" : "John",
"departments" :
[
{ "dep_id" : "d001", "dep_name" : "Sales" },
{ "dep_id" : "d004", "dep_name" : "Quality M" }
]
}
}
Run Code Online (Sandbox Code Playgroud)
2.聚合框架解决方案
更好的解决方案是使用聚合框架而不是Map-Reduce.在这里,您将使用$lookup
stage从中获取一些数据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" } }
}
}
]);
Run Code Online (Sandbox Code Playgroud)
这将导致
{
"_id" : "1234",
"first_name" : "John",
"departments" :
[
{ "dep_id" : "d001", "dep_name" : "Sales" },
{ "dep_id" : "d004", "dep_name" : "Quality M" }
]
}
Run Code Online (Sandbox Code Playgroud)