Tengo un documento como:
[ {_id:1, field: {array: [1,2,3,4,1,1] }}, {_id:2, field: {array: [5,1,1,1,1,1] }}, {_id:3, field: {array: [3,2,3,4,1,2] }} ]Quiero contar los elementos de la matriz que equivalen a 1.
El resultado es:
[ {_id: 1, count: 3}, {_id: 2, count: 5}, {_id: 3, count: 1} ]Puede probar una consulta de agregación,
$filter para iterar el ciclo de una matriz y verificar la condición si el valor es 1$size para obtener los elementos totales de la matriz filtrada db.collection.aggregate([ { $project: { count: { $size: { $filter: { input: "$field.array", cond: { $eq: ["$$this", 1] } } } } } } ])La segunda opción posible,
$reduce para iterar el ciclo de la matriz$cond para verificar si el valor es igual a 1$add más uno en initialValue de lo contrario devuelve el mismo número db.collection.aggregate([ { $project: { count: { $reduce: { input: "$field.array", initialValue: 0, in: { $cond: [ { $eq: ["$$this", 1] }, { $add: ["$$value", 1] }, "$$value" ] } } } } } ])Aquí hay una solución extendida que obtendrá la distribución del valor de todos los elementos de field.array .
db.foo.aggregate([ {$addFields: {distrib: {$reduce: { input: "$field.array", initialValue: {"1":0,"2":0,"3":0,"4":0,"5":0}, in: { "1":{$add:["$$value.1",{$toInt:{$eq:[1,"$$this"]}}]}, "2":{$add:["$$value.2",{$toInt:{$eq:[2,"$$this"]}}]}, "3":{$add:["$$value.3",{$toInt:{$eq:[3,"$$this"]}}]}, "4":{$add:["$$value.4",{$toInt:{$eq:[4,"$$this"]}}]}, "5":{$add:["$$value.5",{$toInt:{$eq:[5,"$$this"]}}]} } }} }} ]); Y, por lo general, la siguiente pregunta es cómo obtener distribuciones en varios documentos, lo que en cierto modo es "más fácil" porque $bucket funciona en una canalización de documentos:
db.foo.aggregate([ {$unwind: "$field.array"}, {$bucket: { groupBy: "$field.array", boundaries: [1,2,3,4,5,6,7,8,9,10], output: { n: {$sum:1} } }} ]); Como alternativa, puede agregar esta etapa después de la etapa $addFields/$reduce . Produce matrices desordenadas de 1 objeto de los cuales solo el campo n es interesante, pero puede obtener fácilmente el valor en el lado del cliente con doc['1'][0]['n'], doc['2'][0]['n'] , etc
,{$facet: { "1": [ {$group: {_id:null, n:{$sum:"$distrib.1"}}} ], "2": [ {$group: {_id:null, n:{$sum:"$distrib.2"}}} ], "3": [ {$group: {_id:null, n:{$sum:"$distrib.3"}}} ], "4": [ {$group: {_id:null, n:{$sum:"$distrib.4"}}} ], "5": [ {$group: {_id:null, n:{$sum:"$distrib.5"}}} ] }} Si realmente desea simplificar la estructura de devolución, agregue esta etapa al final para colapsar los datos [0]['n'] :
,{$addFields: { "1": {$let:{vars:{q:{$arrayElemAt:["$1",0]}},in: "$$qn"}}, "2": {$let:{vars:{q:{$arrayElemAt:["$2",0]}},in: "$$qn"}}, "3": {$let:{vars:{q:{$arrayElemAt:["$3",0]}},in: "$$qn"}}, "4": {$let:{vars:{q:{$arrayElemAt:["$4",0]}},in: "$$qn"}}, "5": {$let:{vars:{q:{$arrayElemAt:["$5",0]}},in: "$$qn"}} }} En MongoDB 5.0, la nueva función $getField hace que esto sea un poco más sencillo:
,{$addFields: { "1": {$getField:{input:{$arrayElemAt:["$1",0]}, field:"n"}} ...