【问题标题】:How to avoid possible null error scenarios in mongodb Aggregate如何避免 mongodb Aggregate 中可能出现的 null 错误情况
【发布时间】:2020-04-16 06:50:37
【问题描述】:

我已经设置了一个相当长的 mongo 聚合查询来将几个 mongo 集合连接在一起,并将它们形成一组字符串字段的输出。只要存在所有必需的值(即:id),查询就可以正常工作,但是在执行 $lookup 时遇到空值或空值时它会中断。

下面是被查询的 PatientFile 集合:

 {
    "no" : "2020921008981",
    "startDateTime" : ISODate("2020-04-01T05:19:02.263+0000")
    "saleId" : "5e8424464475140d19c6941b",
    "patientId" : "5e8424464475140d1955941b"
 }

销售收藏:

 {
    "_id" : ObjectId("5e8424464475140d19c6941b"),
    "invoices" : [
        {
          "billNumber" : "2020921053467", 
          "type" : "CREDIT",
          "insurancePlanId" : "160"
        },
        {
          "billNumber" : "2020921053469", 
          "type" : "DEBIT",
          "insurancePlanId" : "161"
        }
    ],
     "status" : "COMPLETE"
 }

保险收款:

  { 
    "_id" : ObjectId("5b55aca20550de00210a6d25"), 
    "name" : "HIJKL" 
    "plans" : [
       {
         "_id" : "160", 
         "name" : "UVWZ", 
       }, 
       { 
         "_id" : "161", 
         "name" : "LMNO", 
       }
     ]
  }

病人集合:

{ 
  "_id" : ObjectId("5b55cc5c0550de00217ae0f3"),  
  "name" : "TAN NAI",
  "userId" : {
    "number" : "787333128H"
    }
}

这里是聚合查询:

  db.getCollection("patientFile").aggregate([
  { $match: { "startDateTime": { $gte: ISODate("2020-01-01T00:00:00.000Z"), 
                          $lt: ISODate("2020-05-01T00:00:00.000Z") } } },

  {
    $lookup:
        {
            from: "patient",
            let: { pid: "$patientId" },
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $eq: ["$_id", { $toObjectId: "$$pid" }]
                        }
                    }
                },
                { "$project": { "name": 1, "userId.number": 1, "_id": 0 } }
            ],
            as: "patient"
        }
   },
   {
    $lookup:
        {
            from: "sale",
            let: { sid: "$saleId" },
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $eq: ["$_id", { $toObjectId: "$$sid" }]
                        }
                    }
                }
            ],
            as: "sale"
        }
},

{ $unwind: "$sale" },
{ $unwind: "$patient" },

{
    $lookup: {
        from: "insurance",
        let: { pid: {$ifNull:["$sale.bill.insurancePlanId", [] ]} },
        pipeline: [
            {
                $unwind: "$plans"
            },
            {
                $match: { $expr: { $in: ["$plans._id", "$$pid"] } }
            },
            {
                $project: { _id: 0, name: 1 }
            }
        ],
        as: "insurances"
       }
  },

  { $match: { "insurances.name": { $exists: true, $ne: null } } },


  {
    $addFields: {

        invoice: {
            $reduce: {
                input:  {$ifNull:["$sale.bill.billNumber", [] ]},
                initialValue: "",
                in: {
                    $cond: [{ "$eq": ["$$value", ""] }, "$$this", { $concat: ["$$value", "\n", "$$this"] }]
                }
            }
        },
        insurances: {
            $reduce: {
                input:  {$ifNull:["$insurances.name", [] ]},
                initialValue: "",
                in: {
                    $cond: [{ "$eq": ["$$value", ""] }, "$$this", { $concat: ["$$value", "\n", "$$this"] }]
                }
             }
          }

       }
  },


  {
    "$project": {
        "startDateTime": 1,
        "patientName": "$patient.name",
        "invoice": 1,
        "insurances": 1
       }
     }

   ],

      { allowDiskUse: true }

 )

错误:

Unable to execute the selected commands

Mongo Server error (MongoCommandException): Command failed with error 241 (ConversionFailure): 'Failed to parse objectId '' in $convert with no onError value: Invalid string length for parsing to OID, expected 24 but found 0' on server localhost:27017. 

The full response is:
 { 
    "ok" : 0.0, 
    "errmsg" : "Failed to parse objectId '' in $convert with no onError value: Invalid string length for parsing to OID, expected 24 but found 0", 
    "code" : NumberInt(241), 
    "codeName" : "ConversionFailure"
 }

作为我找到的解决方案,使用了$ifNull,但此错误不断出现。在这种情况下采取的最佳步骤是什么?

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    我看到了几种方法:

    • 不是将字符串值转换为 ObjectId 进行测试,而是将 ObjectId 转换为字符串

      $match: {
          $expr: {
              $eq: [{$toString: "$_id"}, "$$pid" ]
          }
      }
      
    • 使用$convert 并提供onError 和/或onNull 值,而不是$toObjectId 帮助器:

      $match: {
          $expr: {
              $eq: ["$_id", { $convert: {
                                     input: "$$pid",
                                     to: "objectId", 
                                     onError: {error:true},
                                     onNull: {isnull:true}
              }}]
          }
      }
      

    【讨论】:

    • 我尝试了第一个,它似乎工作正常。问题是这需要很多时间。有没有办法优化这个聚合查询?
    • 查找的管道形式不能非常有效地使用索引。如果您要在 $addFields 阶段将字符串转换为 objectId,则可以使用更好地使用索引的 localField/foreignField 形式的查找。
    • 我明白了。如果我只从加入的集合中获取所需的字段,那么我可以减少传递的数据怎么样?
    • 这也是个好主意。获取有关查找管道中正在发生的事情的详细信息并不容易,因此您必须在相当大的数据集上尝试两者,看看它们的表现如何。
    猜你喜欢
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 2014-08-24
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多