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" }
}
}
])
我有以下架构:
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" }
}
}
])