假设我们有两种不同类型的文件。第一类商店addresses
和第二类商店cars and boats for each person identified by its national document (dni)
。
考虑以下4个文件:
/* 1 */
{
"_id" : {
"i" : ObjectId("575e6522d51ef71dbe128bd0"),
"dni" : "72999995X"
},
"data" : {
"addresses" : [
{
"type" : "avenue",
"name" : "gran via",
"number" : 112
},
{
"type" : "street",
"name" : "mayor",
"number" : 23
}
]
}
}
/* 2 */
{
"_id" : {
"i" : ObjectId("575e657dd51ef71dbe128bd1"),
"dni" : "72999994B"
},
"data" : {
"addresses" : [
{
"type" : "avenue",
"name" : "gran via",
"number" : 112
},
{
"type" : "road",
"name" : "N-112",
"km" : 430
},
{
"type" : "road",
"name" : "N-112",
"km" : 440
}
]
}
}
/* 3 */
{
"_id" : {
"i" : ObjectId("575e65cdd51ef71dbe128bd2"),
"dni" : "72999995X"
},
"data" : {
"cars" : [
{
"fuel" : "gas",
"color" : "black",
"brand" : "BMW"
},
{
"fuel" : "gas",
"color" : "white",
"brand" : "Mercedes"
}
],
"boats" : [
{
"year" : 1998,
"engines" : 1,
"tank" : 2250
},
{
"year" : 2015,
"engines" : 2,
"tank" : 4100
}
]
}
}
/* 4 */
{
"_id" : {
"i" : ObjectId("575e664ad51ef71dbe128bd3"),
"dni" : "72999994B"
},
"data" : {
"cars" : [
{
"fuel" : "diesel",
"color" : "gray",
"brand" : "BMW"
},
{
"fuel" : "gas",
"color" : "blue",
"brand" : "Opel"
},
{
"fuel" : "gas",
"color" : "black",
"brand" : "BMW"
}
],
"boats" : [
{
"year" : 2001,
"engines" : 2,
"tank" : 2550
},
{
"year" : 2014,
"engines" : 3,
"tank" : 4000
}
]
}
}
问题是......我怎样才能从每个数组中获得符合适用于2个以上不同文档的条件的项目?
例如......谁住在mayor
并且拥有gas
辆汽车和项目匹配值。
这是我的方法:
db.getCollection('test').aggregate([
{'$group': {'_id': {'dni': '$_id.dni'}, 'data': {'$addToSet':'$data'}}},
{'$match': {'$and': [{'data.cars.fuel':'gas'}, {'data.addresses.name':'mayor'}]}},
{'$unwind': '$data'},
{'$unwind': {'path': '$data.cars', 'preserveNullAndEmptyArrays': true}},
{'$unwind': {'path': '$data.addresses', 'preserveNullAndEmptyArrays': true}},
{'$match': {'$or': [{'data.cars.fuel':'gas'}, {'data.addresses.name':'mayor'}]}},
{'$project': {'data.cars': 1, 'data.addresses': 1}}
])
这个管道实际上返回了我想要的东西:
/* 1 */
{
"_id" : {
"dni" : "72999995X"
},
"data" : {
"cars" : {
"fuel" : "gas",
"color" : "black",
"brand" : "BMW"
}
}
}
/* 2 */
{
"_id" : {
"dni" : "72999995X"
},
"data" : {
"cars" : {
"fuel" : "gas",
"color" : "white",
"brand" : "Mercedes"
}
}
}
/* 3 */
{
"_id" : {
"dni" : "72999995X"
},
"data" : {
"addresses" : {
"type" : "street",
"name" : "mayor",
"number" : 23
}
}
}
但是我必须更改$and by $or in $match stage
,因为在$unwind
阶段之后,每个值都转到了不同的文档。
如果是GENERIC解决方案,那就没关系,但事实并非如此。如果现在我想获得同时拥有'gas' cars
和boats with 2+ engines
的人
$match
阶段看起来像这样:
{'$match': {'$and': [{'data.cars.fuel':'gas'}, {'data.boats.engines':{'$gt':1}}]}},
但两次都应该是$and
,因为在$unwind
之后,汽车和船只都属于同一份文件。
(例如:)
/* 6 */
{
"_id" : {
"dni" : "72999994B"
},
"data" : {
"cars" : {
"fuel" : "gas",
"color" : "black",
"brand" : "BMW"
},
"boats" : {
"year" : 2014,
"engines" : 3,
"tank" : 4000
}
}
}
是否有可能$unwind
他们使用不同的文件?
否则......如何在不改变架构的情况下到达通用管道来实现各种查询?