我在LEGO建筑中有一系列乐高零件的id。
// building collection
{
"name": "Gingerbird House",
"buildingTime": 45,
"rating": 4.5,
"elements": [
{
"_id": 23,
"requiredElementAmt": 14
},
{
"_id": 13,
"requiredElementAmt": 42
}
]
}
然后
//elements collection
{
"_id": 23,
"name": "blue 6 dots brick",
"availableAmt":20
}
{
"_id": 13,
"name": "red 8 dots brick",
"availableAmt":50
}
{"_id":254,
"name": "green 4 dots brick",
"availableAmt":12
}
我如何才能找到建造建筑物的可能性?即仅当建筑文档中的“elements”数组包含我在仓库中的元素(元素集合)需要较少(或相等)的某些元素时,数据库才会返回建筑物。
在SQL中(我最近来的)我会写SELECT * FROM building WHERE id NOT IN(SELECT fk_building FROM building_elemnt_amt WHERE fk_element NOT IN (1, 3))
之类的东西
提前谢谢!
答案 0 :(得分:1)
我不会假装我在没有任何比较的情况下得到它在SQL中的工作方式,但是在mongodb中你可以做类似的事情:
db.buildings.find({/* building filter, if any */}).map(function(b){
var ok = true;
b.elements.forEach(function(e){
ok = ok && 1 == db.elements.find({_id:e._id, availableAmt:{$gt:e.requiredElementAmt}}).count();
})
return ok ? b : false;
}).filter(function(b){return b});
或
db.buildings.find({/* building filter, if any */}).map( function(b){
var condition = [];
b.elements.forEach(function(e){
condition.push({_id:e._id, availableAmt:{$gt:e.requiredElementAmt}});
})
return db.elements.find({$or:condition}).count() == b.elements.length ? b : false;
}).filter(function(b){return b});
最后一个应该更快一点,但我没有测试。如果性能是关键,那么mapReduce它必须更好地并行运行子查询。
注意:上面的示例假设buildings.elements
没有具有相同ID的元素。否则,elements
数组需要在b.elements.forEach
之前进行预处理,以计算非唯一ID的总requiredElementAmt
。
使用find选择buildings
集合中的所有/部分文档:
db.buildings.find({/* building filter, if any */})
返回一个游标,我们使用map进行迭代,将函数应用于每个文档:
map(function(b){...})
对于每个elements
文档buildings
,函数本身会迭代b
数组:
b.elements.forEach(function(e){...})
elements
集合中的
db.elements.find({_id:e._id, availableAmt:{$gte:e.requiredElementAmt}}).count();
:
elements._id == e._id
and
elements.availableAmt >= e.requiredElementAmt
直到第一次请求返回0.
由于elements._id
是唯一的,因此该子查询返回0或1。
表达式ok = ok && 1 == 0
中的前0个将ok
变为false,因此elements
数组的其余部分将在不触及数据库的情况下进行迭代。
该函数返回当前buildings
文档或false:
return ok ? b : false
因此map函数的结果是一个数组,包含可以构建的完整buildings
文档,或者对于缺少至少1个资源的文档,则为false。
然后我们filter这个数组去掉了false
元素,因为它们没有有用的信息:
filter(function(b){return b})
它会返回一个新数组,其中包含function(b){return b}
未返回false
的所有元素,即只有完整的buildings
个文档。