我是mongodb的新手。假设以下内容。一个集合x,y和z中有3种文档。
docs = [{
"item_id": 1
"type": "x"
},
{
"item_id": 2
"type": "x"
},{
"item_id": 3
"type": "y",
"relavent_item_ids": [1, 2]
},
{
"item_id": 3
"type": "y",
"relavent_item_ids": [1, 2, 3]
},{
"item_id": 4
"type": "z",
}]
我想得到以下内容。
z
的文档x
类型的item_id
不在relavent_item_ids
类型的y
文档中的所有文档。item_id
字段。我尝试做match
$in
,但这返回了我所有的记录,我无法弄清楚如何处理y
类型的文档子集。
答案 0 :(得分:2)
您可以使用以下查询
const item_ids = (await db.collection.find({ "type": "y" })).map(({ relavent_item_ids }) => relavent_item_ids)
const result = db.collection.find({
"item_id": { "$exists": true },
"type": { "$ne": "z", "$eq": "x" },
"relavent_item_ids": { "$nin": item_ids }
})
console.log({ result })
忽略类型为z的文件->使用不等于查询运算符的$ne
来过滤z
类型。
获取所有类型为item_id不在类型y的relavent_item_ids中的类型为x的所有文档->使用$expr
来匹配相同的文档字段。
结果应具有item_id字段->使用$exists
查询运算符。
答案 1 :(得分:1)
解决方案:
db.test.aggregate( [
{
$facet: {
firstQuery: [
{
$match: { type: { $eq: "x", $ne: "z" } }
},
{
$project: {
item_id : 1, _id: 0
}
}
],
secondQuery: [
{
$match: { type: "y" }
},
{
$group: {
_id: null,
relavent: { $push: "$relavent_item_ids" }
}
},
{
$project: {
relavent: {
$reduce: {
input: "$relavent",
initialValue: [ ],
in: { $setUnion: [ "$$value", "$$this" ] }
}
}
}
}
]
}
},
{
$addFields: { secondQuery: { $arrayElemAt: [ "$secondQuery", 0 ] } }
},
{
$project: {
result: {
$filter: {
input: "$firstQuery" ,
as: "e",
cond: { $not: [ { $in: [ "$$e.item_id", "$secondQuery.relavent" ] } ] }
}
}
}
},
] )
使用问题帖中的输入文档,然后再将以下文档添加到集合中
:{
"item_id": 11,
"type": "x",
}
:仅此文档的item_id
(值11
)将显示在输出中。
聚合使用$facet
通过一次传递进行两个单独的查询。第一个查询将所有“ x”类型(并忽略“ z”类型)作为数组。第二个查询获取具有唯一值的relavent_item_ids
数组(来自“ y”类型的文档)。最后的$project
阶段使用以下条件过滤第一个查询结果数组:
获取所有不在type_id中的x类型的文档 y个文档的relavent_item_ids
答案 2 :(得分:0)
我不确定这是否是一种优雅的解决方案。
db.getCollection('test').aggregate([
{
"$unwind": {
"path": "$relavent_item_ids",
"preserveNullAndEmptyArrays": true
}
},
{
"$group": {
"_id":null,
"relavent_item_ids": {"$addToSet":"$relavent_item_ids"},
"other_ids": {
"$addToSet":{
"$cond":[
{"$eq":["$type", "x"]},
"$item_id",
null
]
}
}
}
},
{
"$project":{
"includeIds": {"$setDifference":["$other_ids", "$relavent_item_ids"]}
}
},
{
"$unwind": "$includeIds"
},
{
"$match": {"includeIds":{"$ne":null}}
},
{
"$lookup":{
"from": "test",
"let": { "includeIds": "$includeIds"},
"pipeline": [
{ "$match":
{ "$expr":
{ "$and":
[
{ "$eq": [ "$item_id", "$$includeIds" ] },
{ "$eq": [ "$type", "x" ] }
]
}
}
}
],
"as": "result"
}
},
{
"$unwind": "$result"
},
])