如何在 $project 中使用带有过滤器内部数组的聚合
how to use aggregate with filter inner array inside $project
目前我正在使用 mongodb 来存储有关我的表单和回复的数据,当我在我的集合中使用查找时,以下数据是 returned:
[
{
"_id": 1,
"forms": [
{
"current_version": 0,
"history": [
{
"content": [{"label": "vrau"}],
"responses": [
{"client_id": 1, "response": [{"field": "vrau1"}]},
{"client_id": 1, "response": [{"field": "vrau1"}]},
{"client_id": 2, "response": [{"field": "vrau2"}]},
{"client_id": 2, "response": [{"field": "vrau2"}]},
],
}
],
}
],
"name": "Testing",
},
{
"_id": 2,
"forms": [
{
"current_version": 1,
"history": [
{
"content": [{"label": "vrau"}],
"responses": [
{"client_id": 1, "response": [{"field": "vrau11"}]},
{"client_id": 1, "response": [{"field": "vrau11"}]},
{"client_id": 2, "response": [{"field": "vrau22"}]},
{"client_id": 2, "response": [{"field": "vrau22"}]},
],
}
],
}
],
"name": "Testing2",
},
]
我想做的是 return 只有来自第一个文档的响应:_id
= 1 其中 client_id
等于 1。因此,以下输出是我想要的。
[{
"_id": 1,
"forms": [
{
"history": [
{
"responses": [
{"client_id": 1, "response": [{"field": "vrau1"}]},
{"client_id": 1, "response": [{"field": "vrau1"}]},
],
}
],
}
]
}]
但我的查询是 return 将表单字段清空,这就是我想要做的:
collection.aggregate([
{
"$match" : {
"_id" : 1,
}
},
{
"$project": {
"forms": {
"$filter": {
"input": "$forms",
"as": "form",
"cond": { "$and":[
{"$eq": [ "$$form.history.responses.client_id", 1 ]}
]
}
}
}
}
}
])
上面的代码有什么问题?
一种方法是使用 $reduce
将您的多级数组“扁平化”为一个响应数组。然后,剩下的就是 $filter
您需要的回复:
db.collection.aggregate([
{$match: {_id: 1}},
{
$project: {
responses: {
$reduce: {
input: "$forms",
initialValue: [],
in: {
$concatArrays: [
{
$reduce: {
input: "$$this.history",
initialValue: [],
in: {$concatArrays: ["$$value", "$$this.responses"]}
}
},
"$$value"
]
}
}
}
}
},
{
$project: {
responses: {
$filter: {
input: "$responses", as: "item", cond: {$eq: ["$$item.client_id", 1]}
}
}
}
}
])
目前我正在使用 mongodb 来存储有关我的表单和回复的数据,当我在我的集合中使用查找时,以下数据是 returned:
[
{
"_id": 1,
"forms": [
{
"current_version": 0,
"history": [
{
"content": [{"label": "vrau"}],
"responses": [
{"client_id": 1, "response": [{"field": "vrau1"}]},
{"client_id": 1, "response": [{"field": "vrau1"}]},
{"client_id": 2, "response": [{"field": "vrau2"}]},
{"client_id": 2, "response": [{"field": "vrau2"}]},
],
}
],
}
],
"name": "Testing",
},
{
"_id": 2,
"forms": [
{
"current_version": 1,
"history": [
{
"content": [{"label": "vrau"}],
"responses": [
{"client_id": 1, "response": [{"field": "vrau11"}]},
{"client_id": 1, "response": [{"field": "vrau11"}]},
{"client_id": 2, "response": [{"field": "vrau22"}]},
{"client_id": 2, "response": [{"field": "vrau22"}]},
],
}
],
}
],
"name": "Testing2",
},
]
我想做的是 return 只有来自第一个文档的响应:_id
= 1 其中 client_id
等于 1。因此,以下输出是我想要的。
[{
"_id": 1,
"forms": [
{
"history": [
{
"responses": [
{"client_id": 1, "response": [{"field": "vrau1"}]},
{"client_id": 1, "response": [{"field": "vrau1"}]},
],
}
],
}
]
}]
但我的查询是 return 将表单字段清空,这就是我想要做的:
collection.aggregate([
{
"$match" : {
"_id" : 1,
}
},
{
"$project": {
"forms": {
"$filter": {
"input": "$forms",
"as": "form",
"cond": { "$and":[
{"$eq": [ "$$form.history.responses.client_id", 1 ]}
]
}
}
}
}
}
])
上面的代码有什么问题?
一种方法是使用 $reduce
将您的多级数组“扁平化”为一个响应数组。然后,剩下的就是 $filter
您需要的回复:
db.collection.aggregate([
{$match: {_id: 1}},
{
$project: {
responses: {
$reduce: {
input: "$forms",
initialValue: [],
in: {
$concatArrays: [
{
$reduce: {
input: "$$this.history",
initialValue: [],
in: {$concatArrays: ["$$value", "$$this.responses"]}
}
},
"$$value"
]
}
}
}
}
},
{
$project: {
responses: {
$filter: {
input: "$responses", as: "item", cond: {$eq: ["$$item.client_id", 1]}
}
}
}
}
])