我正在使用MongoDB 4和Python3。我有3个集合。第一个集合在其他集合上有2个引用字段。
示例:
User {
_id : ObjectId("5b866e8e06a77b30ce272ba6"),
name : "John",
pet : ObjectId("5b9248cc06a77b09a496bad0"),
car : ObjectId("5b214c044ds32f6bad7d2"),
}
Pet {
_id : ObjectId("5b9248cc06a77b09a496bad0"),
name : "Mickey",
}
Car {
_id : ObjectId("5b214c044ds32f6bad7d2"),
model : "Tesla"
}
因此,一位用户有一辆汽车和一只宠物。我需要查询User集合,并查找是否有一个用户的宠物名为“ Mickey”,而汽车的型号为“ Tesla”。
我尝试过这个:
db.user.aggregate([{
$project : {"pet.name" : "Mickey", "car.model" : "Tesla" }
}])
但是当我只有一个文档包含此数据时,它返回了很多数据。我在做什么错了?
答案 0 :(得分:1)
您需要在此处使用$lookup
聚合。
类似这样的东西
db.users.aggregate([
{ "$lookup": {
"from": Pet.collection.name,
"let": { "pet": "$pet" },
"pipeline": [
{ "$match": { "$expr": { "$eq": ["$_id", "$$pet"] }, "name" : "Mickey"}}
],
"as": "pet"
}},
{ "$lookup": {
"from": Car.collection.name,
"let": { "car": "$car" },
"pipeline": [
{ "$match": { "$expr": { "$eq": ["$_id", "$$car"] }, "model" : "Tesla"}}
],
"as": "car"
}},
{ "$match": { "pet": { "$ne": [] }, "car": { "$ne": [] } }},
{ "$project": { "name": 1 }}
])
答案 1 :(得分:1)
@AnthonyWinzlet发布的答案有一个缺点,那就是它需要翻阅用户集合中的所有文档并执行$lookup
,这是相对昂贵的。因此,根据您的Users
集合的大小,这样做可能会更快:
users.pet
和users.car
上放置索引:db.users.createIndex({pet: 1, car: 1})
cars.model
上放置索引:db.cars.createIndex({model: 1})
pets.name
上放置索引:db.pets.createIndex({name: 1})
那么您可以简单地做到这一点:
"Tesla"
汽车的列表:db.cars.find({model: "Tesla"})
"Mickey"
只宠物的列表:db.pets.find({name: "Mickey"})
db.users.find({car: { $in: [<ids from cars query>] }, pet: { $in: [<ids from pets query>] }})
这很容易阅读和理解,而且所有三个查询都完全被索引覆盖,因此可以期望它们尽可能快。