MongoDB 查询语法:如何在 $in 中使用 $isNull (pymongo api)

Posted

技术标签:

【中文标题】MongoDB 查询语法:如何在 $in 中使用 $isNull (pymongo api)【英文标题】:MongoDB Query Syntax: how to use $isNull inside $in (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 而不是一个数组。 【参考方案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"] ] ]) 以了解发生了什么。

以上是关于MongoDB 查询语法:如何在 $in 中使用 $isNull (pymongo api)的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB in Go (golang) with mgo:如何使用逻辑运算符进行查询?

MongoDB $或查询

使用 $in 查询在 mongodb 中更新?

如何在 mongodb 中运行此查询?

Solr如何使用in语法查询

mongodb 使用 $in 查询多对