Pymongo在子文档中发现价值

时间:2018-09-17 15:41:55

标签: python mongodb pymongo

我正在使用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"  } 
}])

但是当我只有一个文档包含此数据时,它返回了很多数据。我在做什么错了?

2 个答案:

答案 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集合的大小,这样做可能会更快:

  1. users.petusers.car上放置索引:db.users.createIndex({pet: 1, car: 1})
  2. cars.model上放置索引:db.cars.createIndex({model: 1})
  3. pets.name上放置索引:db.pets.createIndex({name: 1})

那么您可以简单地做到这一点:

  1. 获取所有匹配的"Tesla"汽车的列表:db.cars.find({model: "Tesla"})
  2. 获取所有匹配的"Mickey"只宠物的列表:db.pets.find({name: "Mickey"})
  3. 找到您感兴趣的用户:db.users.find({car: { $in: [<ids from cars query>] }, pet: { $in: [<ids from pets query>] }})

这很容易阅读和理解,而且所有三个查询都完全被索引覆盖,因此可以期望它们尽可能快。