问题
Let's say I have the following document structure:
{
"_id": "ID",
"array": [
{
"a": "A",
"b": "B",
"c": {
"x": true,
"y": true,
"z": false
}
},
{
"a": "A",
"b": "B"
},
{
"a": "A",
"b": "B"
"c": {
"s": true
}
}
]
}
I am trying to do an aggregation which gives me this type of output:
{
"_id": "ID",
"array": [
{
"a": "A",
"b": "B",
"c": 2
},
{
"a": "A",
"b": "B",
"c": 0
},
{
"a": "A",
"b": "B"
"c": 1
}
]
}
So what I want to do is to, instead of the document c
, return the number of elements with true
as value. And as in the example, the c
field does not necessarily exist (in which case I want to return 0), and when it does, it's subfields are not necessarily the same as other c
subfields in the array. Let's say I am doing the aggregation:
db.collection.aggregate([
{"$match": {<conditions>}},
{"$project": {
"array.a": 1,
"array.b": 1,
"array.c": <?>,
}}
])
How can I adjust "array.c"
in the projection to accomplish what I'm after?
回答1:
You need to have at least MongoDB v3.4.4
Projecting "array.a": 1
will return ["A", "A", "A"]
.
Since your array
field is an array, we need to use $map
operator for iteration.
To iterate over object keys, we need to transform it into array with $objectToArray operator.
"c": { "c": [
"x": true, {k: "x", v: true},
"y": true, -> {k: "y", v: true},
"z": false {k: "z", v: false},
} ]
Then, we apply $filter
operator to get just the k:v
pairs whose v
is true
.
db.collection.aggregate([
{
$match: {}
},
{
$project: {
array: {
$map: {
input: "$array",
as: "arr",
in: {
a: "$$arr.a",
b: "$$arr.b",
c: {
$size: {
$filter: {
input: {
$objectToArray: {
$ifNull: [
"$$arr.c",
{}
]
}
},
cond: {
$eq: [
"$$this.v",
true
]
}
}
}
}
}
}
}
}
}
])
MongoPlayground
来源:https://stackoverflow.com/questions/60952230/mongodb-project-array-document-size-with-condition