Mongodb: Запрос размера вложенных массивов

0

Вопрос

У меня есть следующая схема:

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

});

И я хотел бы получить только те объекты, у которых есть трассировки с количеством вызовов, превышающим указанное число. Другими словами, размер по крайней мере одного вложенного массива трассировок должен быть больше указанного числа. Я пытаюсь использовать $elemMatch и $size, но безуспешно. На данный момент у меня есть этот код:

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

Где minTraceSize-это int.

Не могли бы вы, ребята, мне помочь? Я был бы вам очень признателен!

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

Лучший ответ

0

Спасибо за образец данных. Мой ответ будет сырым решением MQL, а не решением мангуста, поэтому потребуется некоторый перевод.

Я смог вставить два документа, основанных на ваших комментариях в вашем посте. Мне пришлось изменить идентификатор объекта одного из двух образцов документов, потому что ваши образцы имели одинаковое значение первичного ключа и создавали исключение дубликата ключа.

Вставьте Примеры Данных

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"
})

Если я хочу найти записи, содержащие более 0 элементов в массиве traces Я могу выдать следующее:

Найдите более нуля следов

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

Это возвращает следующее:

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'
  }
]

Найдите более 1 следа

Если вместо этого я хочу найти более одной трассировки, я просто слегка изменяю запрос:

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

... и это возвращает следующие результаты:

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'
  }
]

Вывод

При попытке оценить длину массива в процессоре запросов мы должны выбрать использование $eval опция в качестве синтаксиса для MQL не учитывает ваш вариант использования. То $eval это своего рода универсальный вариант для вещей, которые плохо вписываются в рамки MQL.

ОБНОВЛЕНИЕ № 1 ОП ввела дополнительные требования. Вместо того, чтобы смотреть на количество массивов, мы должны учитывать количество массивов внутри массива (вложенный внутренний массив). Поскольку метод find() с $expr не может оценивать вложенные массивы, мы должны вместо этого использовать структуру агрегации и развернуть внешний массив. В этом примере исходная форма сохраняется в новом поле под названием original затем заменяет root после завершения всей оценки. Поскольку размотка может привести к дубликатам в конвейере, мы завершаем работу с группой $, чтобы подавить дубликаты.

Решение

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

Здравствуйте, спасибо за ваш быстрый ответ! Но это еще не совсем проблема... Я хочу получить размеры следов на втором уровне вложенности. Так что, если у меня есть: { "поля _id": ObjectId в("6175e7ecc62cff004462d4a7"), "следы": [ [ ObjectId в("6175e7ecc62cff004462d4a4"), значение ObjectId("6175e7ecc62cff004462d4a4") ] ], "caller_address": "0x4e204793bc4b8acee32edaf1fbba1f3ea45f7990" }) этот объект, должны вернуться, когда я установил 2 к minTraceSize переменной.
Bruno Medeiros

@БруноМедейрос - пожалуйста, смотрите обновления в моем посте.
barrypicker

это сработало! Большое вам спасибо! =)
Bruno Medeiros

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................