2-х уровневый поиск агрегатов mongodb - PullRequest
0 голосов
/ 03 ноября 2018

У меня есть эти схемы сбора

Schema.users = {
    name : "string",
    username : "string",
    [...]
}

Schema.rooms = {
    name : "string",
    hidden: "boolean",
    user: "string",
    sqmt: "number",
    service: "string"
}

Schema.room_price = {
    morning : "string",
    afternoon: "string",
    day: "string",
    room:'string'
}

Мне нужно объединить пользователей с номерами и указывать для каждого номера конкретные цены.

ожидаемый результат будет

[{
_id:"xXXXXX",
name:"xyz",
username:"xyz",
rooms:[
  {
    _id: 1111,
    name:'room1',
    sqmt: '123x', 
    service:'ppp',
    room_prices: [{morning: 123, afternoon: 321}]
  }
]}]

Первая часть совокупности может быть

db.collection('users').aggregate([
  {$match: cond},
  {$lookup: {
    from: 'rooms',
    let: {"user_id", "$_id"},
    pipeline: [{$match:{expr: {$eq: ["$user", "$$user_id"]}}}],
    as: "rooms"
  }}])

но я не могу понять, как получить цены на номера в одном агрегате

1 Ответ

0 голосов
/ 03 ноября 2018

Если предположить, что room из коллекции room_prices содержит совпадающие данные из name коллекции rooms, то это выражение будет соответствовать "внутреннему" конвейеру $lookup выражение с еще одним $lookup:

  db.collection('users').aggregate([
    { $match: cond },
    { $lookup: {
      from: 'rooms',
      let: { "user_id": "$_id" },
      pipeline: [
       { $match:{ $expr: { $eq: ["$user", "$$user_id"] } } },
       { $lookup: {
         from: 'room_prices',
         let: { 'name': '$name' },
         pipeline: [
           { $match: { $expr: { $eq: [ '$room', '$$name'] } } },
           { $project: { _id: 0, morning: 1, afternoon: 1 } }
         ],
         as: 'room_prices'
       }}
      ],
      as: "rooms"
    }}
  ])

Это также добавляет туда $project, чтобы выбрать только те поля, которые вы хотите из цен. При использовании выразительной формы $lookup вы действительно можете выразить «конвейер», который может быть любой комбинацией конвейерного объединения. Это допускает сложные манипуляции и такие «вложенные поиски».

Обратите внимание, что используя mongoose, вы также можете получить имя коллекции из объекта модели, используя что-то вроде:

 from: RoomPrice.collection.name

Обычно это защита от возможных изменений конфигурации модели, которые могут изменить имя базовой коллекции.


Вы также можете сделать почти то же самое с «устаревшей» формой $lookup до синтаксиса суб-конвейера, доступного от MongoDB 3.6 и выше. Это просто немного больше обработки и реконструкции:

  db.collection('users').aggregate([
    { $match: cond },
    // in legacy form
    { $lookup: {
      from: 'rooms',
      localField: 'user_id',
      foreignField: 'user',
      as: 'rooms'
    }},
    // unwind the output array 
    { $unwind: '$rooms' },
    // lookup for the second collection
    { $lookup: {
      from: 'room_prices',
      localField: 'name',
      foreignField: 'room',
      as: 'rooms.room_prices'
    }},
    // Select array fields with $map
    { $addFields: {
      'rooms': {
        'room_prices': {
          $map: {
            input: '$rooms.room_prices',
            in: {
              morning: '$this.morning',
              afternoon: '$this.afternoon'
            }
          }
        }
      }
    }},
    // now group back to 'users' data
    { $group: {
      _id: '$_id',
      name: { $first: '$name' },
      username: { $first: '$username' },
      // same for any other fields, then $push 'rooms'
      rooms: { $push: '$rooms' }
    }}
  ])

Это немного больше накладных расходов, в основном из-за использования $unwind, а также из-за того, что «выбор поля» на самом деле означает, что вы сначала вернули «целые документы» из room_prices " ", и только после того, как это будет завершено, вы можете выбрать поля.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...