【问题标题】:MongoDB Query Syntax: how to use $isNull inside $in (pymongo api)MongoDB 查询语法:如何在 $in 中使用 $isNull (pymongo api)
【发布时间】:2022-01-14 15:39:12
【问题描述】:

我有一个看起来像这样的文档:

{
"_id": ObjectId(),
"employees": [
   {
        "_id": ObjectId(),
        "sharedBranches": [
            ObjectId(),
            ObjectId()
        ]
   },
{
        "_id": ObjectId()
   }
]
}

我正在尝试在 sharedBranches 字段中返回包含我的输入 ObjectId 的文档,并向下过滤 employees 数组,使其仅包含 sharedBranches 包含我的输入 ObjectId 的对象。

然而,并不是每个employee 对象(即employees 数组中的元素)都包含sharedBranches 字段。我的查询返回一个错误,我很确定这是由于 Nulls,但我无法弄清楚 $isNull 的语法。这是我的查询。 (注意 branch_id 是我正在搜索的输入 ObjectId。

collection = client["collection"]["documents"]
pipeline = [
        {
            "$match": {
                "employees.sharedBranches": {"$elemMatch": {"$eq": ObjectId(branch_id)}},
            }
        },
        {
            "$project": {
                "employees": {
                    "$filter": {
                        "input": "$employees",
                        "as": "employees",
                        "cond": {"$in": [ObjectId(branch_id), {"$ifNull": ["$$employees.sharedBranches", []]}]}
                    }
                }
            }
        }
    ]

此查询返回错误:

OperationFailure: $in requires an array as a second argument, found: object, full error: {'ok': 0.0, 'code': 40081, 'errmsg': '$in requires an array as a second argument, found: object', 'operationTime': Timestamp(1639079887, 1)}

似乎$ifNull 的东西没有对数组进行评估。如果我删除 $ifNull 的东西,并尝试直接在数组上使用 $in (所以我的 $cond 看起来像: "cond": {"$in": [ObjectId(branch_id), "$$employees.sharedBranches"]},

我收到此错误:

OperationFailure: $in requires an array as a second argument, found: string, full error: {'ok': 0.0, 'code': 40081, 'errmsg': '$in requires an array as a second argument, found: string', 'operationTime': Timestamp(1639080588, 1)}

所以我不知道如何解决这个问题。 $ifNull 是我的问题吗?我误认为它根本就需要它吗?

【问题讨论】:

  • found: object - 我很确定 null 不是一个对象。你试过用$type检查数组吗?
  • 很奇怪。我欺骗了您的输入数据并创建了相同的管道并且它有效。 $ifNull expr 正确地将空白(缺失)数组转换为 [] 并且 $filter 工作正常。
  • 我认为发生了这样的事情:构建sharedBranches 数组的东西创建了一个字符串 val 而不是一个数组。

标签: mongodb pymongo


【解决方案1】:

我怀疑您的某些 sharedBranches 字段不是数组,而是具有单个 ID 的字符串。这是一个小技巧,可以嗅探此类事物的 $type,如果该字段不是一个数组(包括如果缺少它将返回 missing),它会将其转换为一个数组:

c = db.foo.aggregate([
    {$project: {
    employees: {$filter: {
            input: "$employees",
            as: "employees",
            cond: {$in: [targetSharedBranchID, {$cond:
                        {if:{$ne:[{$type:'$$employees.sharedBranches'},"array"]},
                         then:  ['$$employees.sharedBranches'], // ah HA!  Create array of one on the fly.
                                                                // OK if missing; will create an empty array.
                         else: '$$employees.sharedBranches'
                        }} ] }
        }}
    }}

    ,{$match: {$expr: {$gt:[{$size:"$employees"},0]} }}

]);

【讨论】:

  • 非常感谢@Buzz。我喜欢这种方法,而且我对 mongo 查询还不够熟悉,无法自己弄清楚。唯一的问题,它不起作用。我仍然收到“第二个元素必须是数组”错误。我玩弄了您的代码,并尝试替换 then 和 else 以返回空数组(例如- then:[],else:[])。当我这样做时,我仍然得到“第二个元素必须是数组错误”。所以这让我相信这不是数据,而是查询。 python api和原始的mongo api有区别吗?
  • @Alan 我刚刚将我的 javascript 转换为 python 并重新运行它并且它有效 - 但当然这是我的数据。我有employee 数组和sharedBranches 作为数组、字符串和完全丢失。 if/then/else 未处理您的数据集中发生的某些事情。尝试:db.foo.aggregate([ {"$unwind": "$employees"} ,{"$match": {"$expr": {"$and":[ {"$ne":[{"$type":"$employees.sharedBranches"},"array"]}, {"$ne":[{"$type":"$employees.sharedBranches"},"missing"]} ]} }} ]) 以了解发生了什么。
猜你喜欢
  • 1970-01-01
  • 2014-12-09
  • 2022-01-23
  • 1970-01-01
  • 2019-02-21
  • 2010-12-17
  • 1970-01-01
相关资源
最近更新 更多