Как $ lookup, избегая нулевых значений в агрегате mongodb - PullRequest
2 голосов
/ 15 апреля 2020

Здесь я использую $ lookup для объединения влево из других коллекций, запрос работает нормально, но когда в некоторых записях отсутствуют значения, он возвращает

errmsg : $in requires an array as a second argument, found: null

Вот запрос структура документа:

{
 "no" : "2020921008981",
 "sale" : {
  "soldItems" : [
    {
        "itemId" : "5b55ac7f0550de00210a3b24", 
    },

    {
        "itemId" : "5b55ac7f0550de00215584re", 
    }
  ], 
 "bills" : [
    {
        "billNo" : "2020921053467", 
        "insurancePlanId" : "160", 
    },

    {
        "billNo" : "2020921053467", 
        "insurancePlanId" : "170", 
     }
   ],
   "visitIds" : [
   5b55ac7f0550de00210a3b24, 5b55ac7f0550de00210a3b24
   ]

  }
}

запрос:

db.case.aggregate([
{
    $lookup: {
        from: "insurance",
        let: { ipids: "$sale.bill.insurancePlanId" },
        pipeline: [
            {
                $unwind: "$coveragePlans"
            },
            {
                $match: { $expr: { $in: ["$coveragePlans._id", "$$ipids"] } }
            },
            {
                $project: { _id: 0, name: 1 }
            }
        ],
        as: "insurances"
    }
},
{
    $lookup: {
        from: "item",
        let: { iid: "$salesOrder.purchaseItems.itemRefId" },
        pipeline: [
            {
                $match: {
                    $expr: {
                        $in: ["$_id", {
                            $map: {
                                input: "$$iid",
                                in: { $toObjectId: "$$this" }
                            }
                        }
                        ]
                    }
                }
            }
        ],
        as: "items"
      }
  }
])

страховая коллекция:

{ 
  "_id" : ObjectId("5b55aca20550de00210a6d25"), 
  "name" : "HIJKL" 
  "coveragePlans" : [
    {
      "_id" : "160", 
      "name" : "UVWZ", 
    }, 
    { 
    "_id" : "161", 
    "name" : "LMNO", 
    }
   ]
 },
{ 
  "_id" : ObjectId("5b55aca20550de00210a6d25"),  
  "name" : "WXYZ"
  "coveragePlans" : [
   {
    "_id" : "169", 
    "name" : "5ABC", 
   }, 
   { 
    "_id" : "170", 
    "name" : "4XYZ", 
    }
  ]
}

коллекция предметов:

{ 
  "_id" : ObjectId("5b55ac7f0550de00210a3b24"), 
  "code" : "ABCDE"
},
{ 
  "_id" : ObjectId("5b55ac7f0550de00215584re"), 
  "code" : "PQRST" 
}

Как избежать этого и эффективно ли проводить нулевые проверки перед прокладкой конвейера на следующих этапах? Пробовал с { $match: { "fieldName": { $exists: true, $ne: null } } }, но он возвращает ошибку mon go относительно формата. Если это путь к go, пожалуйста, укажите этап, на котором я должен это поставить .. Заранее спасибо

Ответы [ 2 ]

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

Вы можете обойти это, не используя $in.

Похоже, что $map выполняется отдельно для каждого документа в коллекции items. Если бы вы запускали карту на этапе $addFields, вы могли бы использовать простую форму поиска, чтобы сопоставить добавленное поле с _id, которое автоматически обрабатывало бы пропущенные null и массив.

При необходимости удалите добавленное поле с этапом $project.

db.case.aggregate([
    {$lookup: {
        from: "insurance",
        let: { ipids: "$sale.bill.insurancePlanId" },
        pipeline: [
            {$unwind: "$coveragePlans"},
            {$match: { $expr: { $in: ["$coveragePlans._id", "$$ipids"] } }},
            {$project: { _id: 0, name: 1 }}
        ],
        as: "insurances"
    }}
    {$addFields:{
        matchArray:{$map: {
                       input: "$$iid",
                       in: { $toObjectId: "$$this" }
        }}
    }},
    {$lookup: {
        from: "item",
        localField: "matchArray",
        foreignField:"_id",
        as: "items"
    }},
    {$project:{
        arrayField: 0 
    }}
])
1 голос
/ 15 апреля 2020

Вы можете использовать $ ifNull оператор

let: { ipids: {$ifNull:["$sale.bill.insurancePlanId", [] ]} },

РЕДАКТИРОВАТЬ: Чтобы пропустить пустые "$salesOrder.purchaseItems.itemRefId" значения

let: { iid: {$filter: {input:"$salesOrder.purchaseItems.itemRefId", cond:{$ne:["$$this", ""]}}} },
...