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)的主要内容,如果未能解决你的问题,请参考以下文章