Pymongo найти значение в поддокументах - PullRequest
0 голосов
/ 17 сентября 2018

Я использую MongoDB 4 и Python 3. У меня есть 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"
}

Итак, у одного пользователя есть одна машина и один питомец. Мне нужно запросить коллекцию пользователей и выяснить, есть ли пользователь, у которого есть домашнее животное с именем «Микки» и автомобиль с моделью «Тесла».

Я пробовал это:

db.user.aggregate([{
    $project : {"pet.name" : "Mickey", "car.model" : "Tesla"  } 
}])

Но он возвращает мне много данных, пока у меня есть только один документ с этими данными. Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

Ответ, опубликованный @AnthonyWinzlet, имеет недостаток, заключающийся в том, что ему необходимо перелистать все документы в коллекции пользователей и выполнить $lookup с, что относительно дорого.Поэтому в зависимости от размера вашей коллекции Users это может быть быстрее:

  1. Поместите индекс на users.pet и users.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>] }})

Это довольно легко прочитать и понять, плюс все три запроса полностью покрыты индексами, поэтому можно ожидать, что они будут настолько быстрыми, насколько это возможно.

0 голосов
/ 17 сентября 2018

Вам необходимо использовать $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 }}
])
...