Mongodb:查询嵌套数组的大小

Mongodb: Query the size of nested arrays

我有以下架构:

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 是一个整数。

你们能帮帮我吗? 非常感谢!

感谢您提供样本数据。我的答案将是原始 MQL 解决方案,而不是猫鼬解决方案,因此需要进行一些翻译。

我能够根据您在 post 中的评论插入两个文档。我不得不更改两个示例文档之一的 ObjectId,因为您的示例具有相同的主键值并且正在生成重复键异常。

插入样本数据

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

这个 returns 以下:

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

... 并且此 returns 具有以下结果:

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 OP 引入了额外的要求。我们必须考虑数组内部数组(嵌套内部数组)的计数,而不是查看数组的计数。由于带有 $expr 的 find() 方法无法评估嵌套数组,我们必须改为使用聚合框架并展开外部数组。此示例将原始表单存储在名为 original 的新字段中,然后在所有计算完成后替换 root。由于展开会导致管道中出现重复项,因此我们最终使用 $group 来抑制重复项。

解决方案

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