Аггрегация из двух коллекций?

Помогите сформировать запрос. Имеются две коллекции со следующими структурами документов

db.xcover
{
    "_id" : ObjectId("5b101caddcab7850a4ba32eb"),
    "connections" : [
        169906699,
        125629607
    ],
    ...other-fields
}

db.dcover
{
    "_id" : 169906699,
    "changed" : true,
    "time" : false,
    ...other-fields
}

связь db.dcover._id in db.xcover.connections

И по сути мне требуется следующее, далее псевдокод запроса:

db.dcover.aggregate([
  {
    $match: {
        $or: [{ changed: true }, { time: true }]
    }
  },
  {
    $lookup: {
      from: 'xcover',
      localField: '_id',
      pipeline: [
        { $match: { $expr: { $in: ['$_id',  '$xcover.connections'] } } },
        { $unwind: '$xcover' }
      ],
       as: 'xcover'
     }
  }
])

Т.е. я хочу сделать выборку из dcover, где поле changed или time установленны в true и агрегировать с данными из xcover в массиве поля connections которого, имеются соответствующие идентификаторы документов dcover.


Ответы (1 шт):

Автор решения: SerjK

Не правильный синтаксис у вас. Вы либо используйте:

$lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }

для одиночного сравнения, либо:

$lookup:
      {
         from: <joined collection>,
         let: { <var_1>: <expression>, …, <var_n>: <expression> },
         pipeline: [ <pipeline to run on joined collection> ],
         as: <output array field>
      }

для множественного. Или, если у вас версия 5.0 и выше:

$lookup:
      {
         from: <foreign collection>,
         localField: <field from local collection's documents>,
         foreignField: <field from foreign collection's documents>,
         let: { <var_1>: <expression>, …, <var_n>: <expression> },
         pipeline: [ <pipeline to run> ],
         as: <output array field>
      }

При этом во втором случае, для доступа к полям из документов объединенной коллекции, их нужно определять в поле let используя "$$variable" синтаксис.

У pipeline нет прямого доступа к объединенным полям документа. Вместо этого определите переменные для объединенных полей документа, используя опцию let, а затем ссылайтесь на переменные в pipeline.

https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/#mongodb-pipeline-pipe.-lookup

В вашем случае будет так(для версии 5.0 и выше):

db.dcover.aggregate([
  {
    $match: {
        $or: [{ changed: true }, { time: true }]
    }
  },
  {
    $lookup: {
      from: 'xcover',
      localField: '_id',
      foreignField: 'connections',
      as: 'xcover'
     }
  }
])



db.dcover.aggregate([
     { $match: { $or: [{ changed: true },{ time: true }] } },
     {
         $lookup: {
              from: 'xcover',
              let: { gid: '$_id' },
              pipeline: [
                 { $match: { $expr: { $in: [ '$$gid', '$connections' ] }}}
              ],
              as: 'xcovers'
          }
     }
])
→ Ссылка