6

In here i'm using $lookup to to a left join from other collections, the query works fine but when some records missing values it returns

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

Heres the querying document structure :

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

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

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

  }
}

the query :

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"
      }
  }
])

insurance collection :

{ 
  "_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", 
    }
  ]
}

item collection :

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

How to avoid this and do null checks effectively before pipe-lining into the next stages? Tried with { $match: { "fieldName": { $exists: true, $ne: null } } } but it returns mongo error regarding the format. If its the way to go please mention the stage i should put that.. Thanks in advance

6
  • you seem to have a typo in your let variable : ipids: "$sales.bill.insurancePlanId", but 'sale' in your scheme Commented Apr 15, 2020 at 14:21
  • easiest thing to do would be to not set null when inserting the data into the database. instead set a blank array [] as the value in that field. Commented Apr 15, 2020 at 14:37
  • @matthPen corrected it thanks Commented Apr 15, 2020 at 15:08
  • Đĵ ΝιΓΞΗΛψΚ, well thats a thing that i have no control of ;) Commented Apr 15, 2020 at 15:08
  • did it solve your problem? Commented Apr 15, 2020 at 15:51

2 Answers 2

2

You can use $ifNull operator

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

EDIT: To skip empty "$salesOrder.purchaseItems.itemRefId" values

let: { iid: {$filter: {input:"$salesOrder.purchaseItems.itemRefId", cond:{$ne:["$$this", ""]}}} },
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer. the previous error went away, but now this occurs. errmsg : Failed to parse objectId in $convert with no onError value: Invalid string length for parsing to OID, expected 24 but found 0
@dineshalwis I've updated my answer, update your second lookup iid variable
1

You can get around that by not using $in.

It looks like this $map is executed separately for every document in the items collection. If you were to run the map in an $addFields stage, you could used the simple form of lookup to match the added field to _id, which would automagically handle missing, null, and array.

Remove the added field with a $project stage if necessary.

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 
    }}
])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.