Mongodb 使用mongo$redact在数组中包含嵌入文档和嵌入文档
对于下面的文档,我需要输出Mongodb 使用mongo$redact在数组中包含嵌入文档和嵌入文档,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,对于下面的文档,我需要输出 1. image arrays which are hsl:1 2. dim.hsl embedded document 主文档 { "_id" : ObjectId("564b17873b91989fcb4e9707"), "type" : "article", "image" : [ { "name" : "i3", "hsl" : 1 }, { "name" : "i1",
1. image arrays which are hsl:1
2. dim.hsl embedded document
主文档
{
"_id" : ObjectId("564b17873b91989fcb4e9707"),
"type" : "article",
"image" : [
{
"name" : "i3",
"hsl" : 1
},
{
"name" : "i1",
"hsl" : 1
},
{
"name" : "i2",
"hsl" : 0,
"ai" : 1
}
],
"dim" : {
"hsl" : {
"path" : "blah"
},
"ai" : {
"path" : "blah"
}
}
我的预期输出如下所示,从图像数组和dim.hsl嵌入文档返回2个文档
{
"result" : [
{
"_id" : ObjectId("564b17873b91989fcb4e9707"),
"type" : "article",
"image" : [
{
"name" : "i3",
"hsl" : 1
},
{
"name" : "i1",
"hsl" : 1
}
],
"dim" : {
"hsl" : {
"path" : "blah"
}
}
}
],
"ok" : 1.0000000000000000
}
下面尝试的代码未返回dim.hsl嵌入文档。
该逻辑作为内联代码包含在代码中。
我不确定mongodb表达式是否用于检查节点是否存在。所以我使用了{$not:{$not:'$hsl'}}。(我希望有更好的办法)
请给我一些建议
db.survey.aggregate([
{ $match: {
image: { $elemMatch: {hsl: 1}}, // docs which have image.hsl
'dim.hsl': { $exists: true} // docs which have dim.hsl
}},
{ $redact : {
$cond: {
if: { $or : [
{$eq: ['$hsl',1]}, // for image array document with hsl:1
{$eq : ['$type' ,'article']},// for main document node
{$not : {$not : '$hsl'}} // for dim -- NOT WORKING
]},
then: "$$DESCEND",
else: "$$PRUNE"
}
}}]);
为什么不能像这样工作的问题在于它的原因和作用。该表达基本上意味着“在每个级别”检查文档,以确定是否满足条件。因此,即使您对存在的“hsl”
键进行了正确的测试,它仍然会“下降”到“path”
,而该条件将不成立,因此没有有效的内容返回树的更高位置
这里唯一真正的方法是完全“忽略”这个关键,基本上是在所有级别提供检查,而不是触及文档的嵌入部分。当然,您可以在以后的操作中删除不需要的值:
db.doc.aggregate([
{“$match”:{
“image.hsl”:1,
“dim.hsl”:{“$exists”:true}
}},
{“$redact”:{
“$cond”:{
“如果”:{
“$or”:[
{“$eq”:['$hsl',1]},
{“$eq”:['$type','article']},
{“$ifNull”:[“$$ROOT.dim.hsl”,false]}
]
},
“然后”:“$$down”,
“else”:“$$PRUNE”
}
}},
{“$project”:{
“类型”:1,
"形象":一,,
“昏暗”:{
“hsl”:“$dim.hsl”
}
}}
])
当然,这并不会真正删除任何内容,因为$ROOT
条件始终为真,这否定了操作的要点
因此,使用和过滤掉元素:
db.doc.aggregate([
{“$match”:{
“image.hsl”:1,
“dim.hsl”:{“$exists”:true}
}},
{“$project”:{
“类型”:1,
“图像”:{
“$setDifference”:[
{“$map”:{
“输入”:“$image”,
“as”:“el”,
“在”:{
“$cond”:[
{“$eq”:[“$$el.hsl”,1]},
{
“名称”:“$$el.name”,
“hsl”:“$$el.hsl”
},
假的
]
}
}},
[错误]
]
},
“昏暗”:{
“hsl”:“$dim.hsl”
}
}}
])
实际上,它通过使用$map
检查每个元素,然后在一个正向true
条件下仅返回所需字段来“过滤”数组内容,或者返回一个false
值,而不是数组元素。然后,通过与另一个具有[false]
的数组/集合进行比较,从数组中删除所有false
值,结果仅为返回的匹配项
另一个子键投影保持不变,现在当然所有的删除只在一个$project
阶段中完成
这将返回您想要的结果:
{
“_id”:ObjectId(“564b17873b91989fcb4e9707”),
“类型”:“文章”,
“图像”:[
{
“名称”:“i3”,
“hsl”:1
},
{
“名称”:“i1”,
“hsl”:1
}
],
“昏暗”:{
“hsl”:{
“路径”:“废话”
}
}
}
为什么不能这样工作的问题在于它的原因和作用。该表达基本上意味着“在每个级别”检查文档,以确定是否满足条件。因此,即使您对存在的“hsl”
键进行了正确的测试,它仍然会“下降”到“path”
,而该条件将不成立,因此没有有效的内容返回树的更高位置
这里唯一真正的方法是完全“忽略”这个关键,基本上是在所有级别提供检查,而不是触及文档的嵌入部分。当然,您可以在以后的操作中删除不需要的值:
db.doc.aggregate([
{“$match”:{
“image.hsl”:1,
“dim.hsl”:{“$exists”:true}
}},
{“$redact”:{
“$cond”:{
“如果”:{
“$or”:[
{“$eq”:['$hsl',1]},
{“$eq”:['$type','article']},
{“$ifNull”:[“$$ROOT.dim.hsl”,false]}
]
},
“然后”:“$$down”,
“else”:“$$PRUNE”
}
}},
{“$project”:{
“类型”:1,
"形象":一,,
“昏暗”:{
“hsl”:“$dim.hsl”
}
}}
])
当然,这并不会真正删除任何内容,因为$ROOT
条件始终为真,这否定了操作的要点
因此,使用和过滤掉元素:
db.doc.aggregate([
{“$match”:{
“image.hsl”:1,
“dim.hsl”:{“$exists”:true}
}},
{“$project”:{
“类型”:1,
“图像”:{
“$setDifference”:[
{“$map”:{
“输入”:“$image”,
“as”:“el”,
“在”:{
“$cond”:[
{“$eq”:[“$$el.hsl”,1]},
{
db.survey.aggregate([
{ "$match": {
"image.hsl": 1,
"dim.hsl": { "$exists": true }
}},
{ "$redact": {
"$cond": {
"if": {
"$or": [
{ "$eq": ['$hsl',1]},
{ "$eq": ['$type' ,'article']},
{ "$ifNull": [ "$hsl", false] },
{ "$ifNull": [ "$$CURRENT.path", false] }
]
},
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}},
{ "$project": {
"type": 1,
"image": 1,
"dim": {
"hsl": "$dim.hsl"
}
}}
])