Mongodb: Consulta o tamanho de matrizes aninhadas

0

Pergunta

Eu tenho o seguinte Esquema:

Schema({
caller_address: {
    type: String,
    required: true,
},
traces: [[{
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Call',
}]]

});

E eu gostaria de recuperar apenas os objetos que tenham traços com as Chamadas de valor maior do que um número especificado. Em outras palavras, o tamanho de pelo menos um aninhados matriz de traços deve ser maior do que um número especificado. Eu estou tentando usar o $elemMatch e $tamanho, mas sem sucesso. Por agora, eu tenho esse código:

CallerTraces.find({ 'traces' : { $elemMatch: { $size : { $gt: minTraceSize } }}})

Onde minTraceSize é um int.

Ei, vocês podem me ajudar? Eu realmente aprecio isso!

arrays mongodb nested
2021-11-23 20:27:28
1

Melhor resposta

0

Obrigado pela amostra de dados. Minha resposta vai ser uma matéria-prima de MQL solução, não um mangusto solução, de modo algum a tradução será necessário.

Eu era capaz de inserir dois documentos, com base em seus comentários no seu post. Eu tive que mudar o ObjectId de um dos documentos de exemplo, porque o seu amostras apresentaram o mesmo valor de chave primária e estava gerando uma chave duplicada exceção.

Inserir Dados De Exemplo

db.CallerTraces.insert(
{
  "_id": ObjectId("6175e7ecc62cff004462d4a6"),
  "traces": [
    [
      ObjectId("6175e7ecc62cff004462d4a4")
    ]
  ],
  "caller_address": "0x4e204793bc4b8acee32edaf1fbba1f3ea45f7990"
})


db.CallerTraces.insert(
{
  "_id": ObjectId("6175e7ecc62cff004462d4a7"),
  "traces": [
    [
      ObjectId("6175e7ecc62cff004462d4a4"),
      ObjectId("6175e7ecc62cff004462d4a4")
    ],
    [
      ObjectId("6175e7ecc62cff004462d4a4")
    ]
  ],
  "caller_address": "0x4e204793bc4b8acee32edaf1fbba1f3ea45f7990"
})

Se eu quero encontrar registros ter mais de 0 itens na matriz traces Eu posso emitir os seguintes:

Encontrar mais do que zero traços

db.CallerTraces.find({ $expr: { $gt: [ { $size: "$traces" }, 0 ] } })

Isso retorna o seguinte:

Enterprise replSet [primary] barrydb> db.CallerTraces.find({ $expr: { $gt: [ { $size: "$traces" }, 0 ] } })
[
  {
    _id: ObjectId("6175e7ecc62cff004462d4a6"),
    traces: [ [ ObjectId("6175e7ecc62cff004462d4a4") ] ],
    caller_address: '0x4e204793bc4b8acee32edaf1fbba1f3ea45f7990'
  },
  {
    _id: ObjectId("6175e7ecc62cff004462d4a7"),
    traces: [
      [
        ObjectId("6175e7ecc62cff004462d4a4"),
        ObjectId("6175e7ecc62cff004462d4a4")
      ],
      [ ObjectId("6175e7ecc62cff004462d4a4") ]
    ],
    caller_address: '0x4e204793bc4b8acee32edaf1fbba1f3ea45f7990'
  }
]

Encontrará mais de 1 de rastreamento

Se, em vez disso, eu quero encontrar mais do que um traço eu simplesmente alterar a consulta de um pouco:

db.CallerTraces.find({ $expr: { $gt: [ { $size: "$traces" }, 1 ] } })

... e esta retorna com os seguintes resultados:

Enterprise replSet [primary] barrydb> db.CallerTraces.find({ $expr: { $gt: [ { $size: "$traces" }, 1 ] } })
[
  {
    _id: ObjectId("6175e7ecc62cff004462d4a7"),
    traces: [
      [
        ObjectId("6175e7ecc62cff004462d4a4"),
        ObjectId("6175e7ecc62cff004462d4a4")
      ],
      [ ObjectId("6175e7ecc62cff004462d4a4") ]
    ],
    caller_address: '0x4e204793bc4b8acee32edaf1fbba1f3ea45f7990'
  }
]

Conclusão

Ao tentar avaliar o comprimento da matriz dentro do processador de consultas devemos optar por usar o $eval opção de como a sintaxe para MQL não considerar seu caso de uso. O $eval é um pouco de um catch-all opção para as coisas que não se encaixam muito bem no MQL quadro.

ATUALIZAÇÃO #1 OP introduziu requisitos adicionais. Em vez de olhar para a contagem da matriz, deve-se considerar a contagem da matriz dentro da matriz (aninhados interior da matriz). Desde o encontrar (em) o método com o $expr não é possível avaliar matrizes aninhadas devemos, em vez disso, use a agregação de quadro e descontrair o exterior da matriz. Este exemplo armazena a forma original em um novo campo chamado original em seguida, substitui a raiz depois de toda a avaliação é completa. Desde relaxamento pode resultar em duplicatas no pipeline nós finalize com um $grupo para suprimir duplicatas.

Solução

db.CallerTraces.aggregate([
    {
        $addFields: {
            "original._id": "$_id",
            "original.traces": "$traces",
            "original.caller_address": "$caller_address"
        }
    },
    {
        $unwind: "$traces"
    },
    {
        $match: { $expr: { $gt: [ { $size: "$traces" }, 1 ] } }
    },
    {
        $replaceRoot: { newRoot: "$original" }
    },
    {
        $group:
        {
            _id: "$_id",
            traces: { "$first": "$traces" },
            caller_address: { "$first": "$caller_address" }
        }
    }
])
2021-11-24 21:42:44

Olá, Obrigado por sua resposta rápida! Mas não é ainda o problema... eu quero ter os Traços tamanhos no segundo nível de aninhamento. Então, se eu tenho: { "_id": ObjectId("6175e7ecc62cff004462d4a7"), "traços": [ [ ObjectId("6175e7ecc62cff004462d4a4"), ObjectId("6175e7ecc62cff004462d4a4") ] ], "caller_address": "0x4e204793bc4b8acee32edaf1fbba1f3ea45f7990" }) Este objeto deve retornar quando eu definir 2 para o minTraceSize variável.
Bruno Medeiros

@BrunoMedeiros - por favor, veja as atualizações no meu post.
barrypicker

ele trabalhou! Muito obrigado! =)
Bruno Medeiros

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................