Как я могу отфильтровать по полю вложенного документа в агрегации mon goose? - PullRequest
0 голосов
/ 30 апреля 2020

Я хочу отфильтровать платежи только указанного пользователя c для платежного поручения. Вот мои схемы:

var PaymentOrderSchema = new Schema({
  name: {type: String, required: true},
  description: {type: String},
  amount: {type: Number},
  charges: [{type: Schema.Types.ObjectId, ref: 'Charge'}],
},

var ChargeSchema = new Schema({
  amount: {type: Number},
  user: {type: Schema.Types.ObjectId, ref: 'User'},
  status: {type: String},
  description: {type: String},
  creation_date:{type: Date}
}

Я пытаюсь использовать агрегацию, но не могу отфильтровать платежи. Когда я использую $ ne вместо $ eq, он возвращает мне расходы, поэтому я знаю, что я на правильном пути. Вот мой фактический код:

const paymentOrder = await PaymentOrder.aggregate([
  {$match: {'_id': mongoose.Types.ObjectId(req.query.payment_order_id)}},
  {$project: {
    charges: {$filter: {
      input: '$charges',
      as: 'charge',
      cond: {$eq: ['$$charge.user._id', mongoose.Types.ObjectId(req.user._id)]}
    }}
  }}
]);

Спасибо!

Ответы [ 2 ]

1 голос
/ 30 апреля 2020

Агрегация выполняется на сервере базы данных, в то время как ссылки расширяются драйвером на стороне клиента, поэтому значение, которое фактически отображается в конвейере, равно

DBRef("User",ObjectId(...),"DatabaseName")

К которому можно получить доступ, как объект

{"$ref":"User", "$id":ObjectId(...), "$db":"DatabaseName"}

Но возникает еще одна проблема: имена полей не могут начинаться с $, поэтому это приведет к ошибке:

{$eq:["$$charge.user.$id",mongoose.Types.ObjectId(req.user._id)]}

Так что вы можете пропустить этот шаг в агрегации и верните документ обратно в mon goose для заполнения, или, если сопоставление на $id - это все, что вам нужно, вы можете использовать $objectToArray, чтобы разбить DBRef, чтобы вы могли сопоставить:

  {$match: {'_id': mongoose.Types.ObjectId(req.query.payment_order_id)}},
  {$unwind: "$charges"},
  {$addFields: {charges:{$objectToArray:"$charges"}}},
  {$match: {charges:{
         $elemMatch:{k:"$id",v:mongoose.Types.ObjectId(req.user._id}
  }}},
  {$group:{_id:"$_id", charges:{$push:{$arrayToObject("$charges"}}}}}

Это возвращает вам DBRef, которые могут быть расширены драйвером, но это соответствует _id документа charges, что, вероятно, не то, что вы хотите.

Однако, однажды у вас есть _id документа об оплате, вы можете использовать $lookup и затем отфильтровать их, но затем мы также должны иметь дело с user как DBref:

  {$match: {'_id': mongoose.Types.ObjectId(req.query.payment_order_id)}},
  {$unwind: "$charges"},
  {$addFields: {chargeId:{$filter:{
         input:$objectToArray:"$charges"
         cond:{$eq:["$$this.k","$id"]}
  }}}}, 
  {$lookup:{
       from:"charge",
       localField:"$chargeId.v",
       foreignField:"$_id",
       as: charges
  }},
  {$unwind:"$charges"},
  {$addField:{chargeUser:{$filter:{
        input:{$objectToArray:"$charges.user"},
        cond:{$eq:["$$this.k","$id"]}
  }}}},
  {$match: {"chargeUser.v":mongoose.Types.ObjectId(req.user._id)}},  
  {$project:{
        chargeUser:0, 
        chargeId:0
  },
  {$group:{
         _id:"$_id", 
         document:{$first:"$$ROOT"}, 
         charges:{$push:"$charges"}
  }},
  {$addFields:{"document.charges":"$charges"}},
  {$replaceRoot:{newRoot:"$document"}}
1 голос
/ 30 апреля 2020

Если я правильно понимаю ваше требование, то мы можем использовать $ lookup с конвейером

примерно так

db.paymentOrder.aggregate([
  {
    $match: {
      _id: ObjectId("5a934e000102030405000003") // replace this hard-coded objectId with mongoose.Types.ObjectId(req.query.payment_order_id)
    }
  },
  {
    $lookup: {
      from: "charge",
      let: {
        chargeIds: "$charges"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $eq: [
                "$user",
                "userId1" // replace this with mongoose.Types.ObjectId(req.user._id)
              ]
            }
          }
        }
      ],
      as: "charges"
    }
  }
])

проверить это Пн go Plaground

надеюсь, что это поможет

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