如何使用主文档中的值查询子文档数组
How to query subdocument array using value in main document
我有一个具有一些属性的文档,其中一个属性是一个子文档数组,我想查找文档并将主文档中的 属性 与子文档中的 属性 进行比较文档数组
下面是文档的一个例子
{
"_id" : ObjectId("54bb897d52a8a302ecafeb03"),
“Contract" : “ABCDE",
“OptimalYear" : 2012,
"Results" : [
{
"Year" : 2011,
"Risk" : 1114
},
{
"Year" : 2012,
"Risk" : 1226
},
{
"Year" : 2013,
"Risk" : 1385.5
}
]
}
我可以
db.CC.find({
Contract: "Jan",
Result: {
$elemMatch: {
Year: 2012
}
}
})
但是我如何在 $elemMatch {Year: OptimalYear}
中使用 OptimalYear 的值
您不能使用标准查询来执行此操作,或者大多数人实际要求的是在处理更新时引用文档中字段的值。没有允许在这些查询中引用字段值的语法。
您可以在聚合框架中执行此操作。自 MongoDB 2.6 以来的现代版本具有 $redact
管道阶段,它有一个很好的处理方式:
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$ifNull": [ "$Year", "$$ROOT.OptimalYear" ] },
"$$ROOT.OptimalYear"
]
},
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}}
])
这基本上评估 $cond
条件或三元语句以查看值实际匹配的位置,然后您将保留该元素。否则当前文档级别将被删除。
$ifNull
is there along with references to $$ROOT
因为这是递归遍历的结构。例如,文档顶部没有 "Year" 字段,因此比较被替换为 "OptimalYear" 值。与自己比较 returns 正确,但在数组中它将与存在的 "Year" 进行比较。
在早期版本中仍然可以这样做,但确实需要更多工作,因此不是最佳方式:
db.collection.aggregate([
{ "$unwind": "$Results" },
{ "$project": {
"Contract": 1,
"OptimalYear": 1,
"Results": 1,
"matched": { "$eq": [ "$Results.Year", "$OptimalYear" ] }
}},
{ "$match": { "matched": true } },
{ "$group": {
"_id": "$_id",
"Contract": { "$first": "$Contract" },
"OptimalYear": { "$first": "$OptimalYear" },
"Results": { "$push": "$Results" }
}}
])
不完全相同,因为那是完全过滤掉没有匹配项的文档,您也可以在以前的版本中通过添加额外的 $match
阶段检查空数组来做到这一点。
我有一个具有一些属性的文档,其中一个属性是一个子文档数组,我想查找文档并将主文档中的 属性 与子文档中的 属性 进行比较文档数组
下面是文档的一个例子
{
"_id" : ObjectId("54bb897d52a8a302ecafeb03"),
“Contract" : “ABCDE",
“OptimalYear" : 2012,
"Results" : [
{
"Year" : 2011,
"Risk" : 1114
},
{
"Year" : 2012,
"Risk" : 1226
},
{
"Year" : 2013,
"Risk" : 1385.5
}
]
}
我可以
db.CC.find({
Contract: "Jan",
Result: {
$elemMatch: {
Year: 2012
}
}
})
但是我如何在 $elemMatch {Year: OptimalYear}
中使用 OptimalYear 的值您不能使用标准查询来执行此操作,或者大多数人实际要求的是在处理更新时引用文档中字段的值。没有允许在这些查询中引用字段值的语法。
您可以在聚合框架中执行此操作。自 MongoDB 2.6 以来的现代版本具有 $redact
管道阶段,它有一个很好的处理方式:
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$ifNull": [ "$Year", "$$ROOT.OptimalYear" ] },
"$$ROOT.OptimalYear"
]
},
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}}
])
这基本上评估 $cond
条件或三元语句以查看值实际匹配的位置,然后您将保留该元素。否则当前文档级别将被删除。
$ifNull
is there along with references to $$ROOT
因为这是递归遍历的结构。例如,文档顶部没有 "Year" 字段,因此比较被替换为 "OptimalYear" 值。与自己比较 returns 正确,但在数组中它将与存在的 "Year" 进行比较。
在早期版本中仍然可以这样做,但确实需要更多工作,因此不是最佳方式:
db.collection.aggregate([
{ "$unwind": "$Results" },
{ "$project": {
"Contract": 1,
"OptimalYear": 1,
"Results": 1,
"matched": { "$eq": [ "$Results.Year", "$OptimalYear" ] }
}},
{ "$match": { "matched": true } },
{ "$group": {
"_id": "$_id",
"Contract": { "$first": "$Contract" },
"OptimalYear": { "$first": "$OptimalYear" },
"Results": { "$push": "$Results" }
}}
])
不完全相同,因为那是完全过滤掉没有匹配项的文档,您也可以在以前的版本中通过添加额外的 $match
阶段检查空数组来做到这一点。