No sentido mais simples, isso apenas segue a forma básica de "notação de ponto" usada pelo MongoDB. Isso funcionará independentemente do membro da matriz em que o membro da matriz interna esteja, desde que corresponda a um valor:
db.mycollection.find({
"someArray.someNestedArray.name": "value"
})
Isso é bom para um valor de "campo único", para corresponder a vários campos, você usaria
$elemMatch
:db.mycollection.find({
"someArray": {
"$elemMatch": {
"name": "name1",
"someNestedArray": {
"$elemMatch": {
"name": "value",
"otherField": 1
}
}
}
}
})
Isso corresponde ao documento que conteria algo com um campo nesse "caminho" correspondente ao valor. Se você pretendia "combinar e filtrar" o resultado para que apenas o elemento correspondido fosse retornado, isso não é possível com a projeção do operador posicional, conforme citado:
Matrizes aninhadas
O operador posicional $ não pode ser usado para consultas que percorrem mais de uma matriz, como consultas que percorrem matrizes aninhadas em outras matrizes, porque a substituição do espaço reservado $ é um valor único
MongoDB moderno
Podemos fazer isso aplicando
$filter
e $map
aqui. O $map
é realmente necessário porque o array "interno" pode mudar como resultado da "filtragem", e o array "externo" obviamente não corresponde às condições quando o "interno" foi retirado de todos os elementos. Novamente seguindo o exemplo de realmente ter várias propriedades para corresponder em cada matriz:
db.mycollection.aggregate([
{ "$match": {
"someArray": {
"$elemMatch": {
"name": "name1",
"someNestedArray": {
"$elemMatch": {
"name": "value",
"otherField": 1
}
}
}
}
}},
{ "$addFields": {
"someArray": {
"$filter": {
"input": {
"$map": {
"input": "$someArray",
"as": "sa",
"in": {
"name": "$$sa.name",
"someNestedArray": {
"$filter": {
"input": "$$sa.someNestedArray",
"as": "sn",
"cond": {
"$and": [
{ "$eq": [ "$$sn.name", "value" ] },
{ "$eq": [ "$$sn.otherField", 1 ] }
]
}
}
}
}
},
},
"as": "sa",
"cond": {
"$and": [
{ "$eq": [ "$$sa.name", "name1" ] },
{ "$gt": [ { "$size": "$$sa.someNestedArray" }, 0 ] }
]
}
}
}
}}
])
Portanto, no array "externo" o
$filter
realmente olha para o $size
da matriz "interna" depois que ela foi "filtrada", para que você possa rejeitar esses resultados quando toda a matriz interna de fato corresponder à observação. MongoDB mais antigo
Para "projetar" apenas o elemento correspondente, você precisa do
.aggregate()
método:db.mycollection.aggregate([
// Match possible documents
{ "$match": {
"someArray.someNestedArray.name": "value"
}},
// Unwind each array
{ "$unwind": "$someArray" },
{ "$unwind": "$someArray.someNestedArray" },
// Filter just the matching elements
{ "$match": {
"someArray.someNestedArray.name": "value"
}},
// Group to inner array
{ "$group": {
"_id": {
"_id": "$_id",
"name": "$someArray.name"
},
"someKey": { "$first": "$someKey" },
"someNestedArray": { "$push": "$someArray.someNestedArray" }
}},
// Group to outer array
{ "$group": {
"_id": "$_id._id",
"someKey": { "$first": "$someKey" },
"someArray": { "$push": {
"name": "$_id.name",
"someNestedArray": "$someNestedArray"
}}
}}
])
Isso permite que você "filtre" as correspondências em matrizes aninhadas para um ou mais resultados no documento.