我想在Mongodb
中分页我的数据。我使用slice
运算符但无法分页我的数据。我希望带上我的行,但不能在这一行中进行分页。
我想只返回2行数据源。
如何解决它
我的查询:
db.getCollection('forms').find({
"_id": ObjectId("557e8c93a6df1a22041e0879"),
"Questions._id": ObjectId("557e8c9fa6df1a22041e087b")
}, {
"Questions.$.DataSource": {
"$slice": [0, 2]
},
"_id": 0,
"Questions.DataSourceItemCount": 1
})
我的收集数据:
/* 1 */
{
"_id" : ObjectId("557e8c93a6df1a22041e0879"),
"QuestionCount" : 2.0000000000000000,
"Questions" : [
{
"_id" : ObjectId("557e8c9ba6df1a22041e087a"),
"DataSource" : [],
"DataSourceItemCount" : NumberLong(0)
},
{
"_id" : ObjectId("557e8c9fa6df1a22041e087b"),
"DataSource" : [
{
"_id" : ObjectId("557e9428a6df1a198011fa55"),
"CreationDate" : ISODate("2015-06-15T09:00:24.485Z"),
"IsActive" : true,
"Text" : "sdf",
"Value" : "sdf"
},
{
"_id" : ObjectId("557e98e9a6df1a1a88da8b1d"),
"CreationDate" : ISODate("2015-06-15T09:20:41.027Z"),
"IsActive" : true,
"Text" : "das",
"Value" : "asdf"
},
{
"_id" : ObjectId("557e98eea6df1a1a88da8b1e"),
"CreationDate" : ISODate("2015-06-15T09:20:46.889Z"),
"IsActive" : true,
"Text" : "asdf",
"Value" : "asdf"
},
{
"_id" : ObjectId("557e98f2a6df1a1a88da8b1f"),
"CreationDate" : ISODate("2015-06-15T09:20:50.401Z"),
"IsActive" : true,
"Text" : "asd",
"Value" : "asd"
},
{
"_id" : ObjectId("557e98f5a6df1a1a88da8b20"),
"CreationDate" : ISODate("2015-06-15T09:20:53.639Z"),
"IsActive" : true,
"Text" : "asd",
"Value" : "asd"
}
],
"DataSourceItemCount" : NumberLong(5)
}
],
"Name" : "er"
}
答案 0 :(得分:1)
虽然这可能与一些真正的争论有关,但最好是更改文档结构以将数组条目“展平”为单个数组。主要原因是由于positional $
operator的当前限制,MongoDB在更新“内部”数组方面没有原子支持的“更新”。
无论如何,由于显而易见的原因,处理起来并不容易。
对于目前的结构,你可以这样做:
db.collection.aggregate([
// Match the required document and `_id` is unique
{ "$match": {
"_id": ObjectId("557e8c93a6df1a22041e0879")
}},
// Unwind the outer array
{ "$unwind": "$Questions" },
// Match the inner entry
{ "$match": {
"Questions._id": ObjectId("557e8c9fa6df1a22041e087b"),
}},
// Unwind the inner array
{ "$unwind": "$Questions.DataSource" }
// Find the first element
{ "$group": {
"_id": {
"_id": "$_id",
"questionId": "$Questions._id"
},
"firstSource": { "$first": "$Questions.DataSource" },
"sources": { "$push": "$Questions.DataSource" }
}},
// Unwind the sources again
{ "$unwind": "$sources" },
// Compare the elements to keep
{ "$project": {
"firstSource": 1,
"sources": 1,
"seen": { "$eq": [ "$firstSource._id", "$sources._id" ] }
}},
// Filter out anything "seen"
{ "$match": { "seen": true } },
// Group back the elements you want
{ "$group": {
"_id": "$_id",
"firstSource": "$firstSource",
"secondSource": { "$first": "$sources" }
}}
])
这样就会给你那个内部数组的“前两个元素”。这是在聚合框架中实现$slice
的基本过程, 是必需的,因为您不能以您尝试的方式使用带有“嵌套数组”的标准投影。
由于聚合框架不支持$slice
,您可以看到执行“分页”将是一个非常可怕且“迭代”的操作,以便“摘取”数组元素。
我可以在这一点建议“扁平化”到单个数组,但同样的“切片”问题适用,因为即使你将“QuestionId”作为“内部”数据的属性,它也有相同的投影选择问题您需要相同的聚合方法。
然后,对于您的数据(对于某些查询操作),这个“看似”并不是很好的结构,但这完全取决于您的使用模式。这种结构适合这种类型的操作:
{
"_id" : ObjectId("557e8c93a6df1a22041e0879"),
"QuestionCount" : 2.0000000000000000,
"Questions" : {
"557e8c9ba6df1a22041e087a": {
"DataSource" : [],
"DataSourceItemCount" : NumberLong(0)
},
"557e8c9fa6df1a22041e087b": {
"DataSource" : [
{
"_id" : ObjectId("557e9428a6df1a198011fa55"),
"CreationDate" : ISODate("2015-06-15T09:00:24.485Z"),
"IsActive" : true,
"Text" : "sdf",
"Value" : "sdf"
},
{
"_id" : ObjectId("557e98e9a6df1a1a88da8b1d"),
"CreationDate" : ISODate("2015-06-15T09:20:41.027Z"),
"IsActive" : true,
"Text" : "das",
"Value" : "asdf"
}
],
"DataSourceItemCount" : NumberLong(5)
}
}
}
这有效:
db.collection.find(
{
"_id": ObjectId("557e8c93a6df1a22041e0879"),
"Questions.557e8c9fa6df1a22041e087b": { "$exists": true }
},
{
"_id": 0,
"Questions.557e8c9fa6df1a22041e087b.DataSource": { "$slice": [0, 2] },
"Questions.557e8c9fa6df1a22041e087b.DataSourceItemCount": 1
}
)
嵌套数组对于许多操作来说并不是很好,特别是更新操作,因为无法获得更新操作的“内部”数组索引。位置$
运算符只会获得“第一个”或“外部”数组索引,并且不能“也”匹配内部数组索引。
使用类似结构的更新涉及“整体”阅读文档,然后在代码中进行操作并写回。没有“保证”文件在这些操作之间的集合中没有变化,除非妥善处理,否则可能导致不一致。
另一方面,如图所示,修改后的结构适用于给定的查询类型,但如果您需要动态搜索或“聚合”您所代表的“外部”,则可能会“糟糕”问题。”
使用MongoDB的数据结构对于“如何使用它”非常主观。因此,最好在为应用程序“确定”最终数据结构设计之前考虑所有使用模式。
因此,您可以注意到所提到的问题和解决方案,或者只是通过标准的“位置”匹配检索“外部”元素,然后在客户端代码中“切片”。
这都是“最适合您应用的问题”。