Mongodb Mongo DB-在组内排序和跳过
我正在使用MongoDB,我想对组中的记录进行排序和跳过 以下是数据示例:Mongodb Mongo DB-在组内排序和跳过,mongodb,aggregation-framework,Mongodb,Aggregation Framework,我正在使用MongoDB,我想对组中的记录进行排序和跳过 以下是数据示例: { "_id" : ObjectId("51cd7274267d959cb9f95cea"), "creation_time" : 100, "delivered" : true, "id" : 1, "user_id" : 10 } 现在我想要的是每个用户的所有文档的\u id(user\u id),其中用户的文档数大于4。在跳过这4个文档之后,我还需要文档的\u id。因此,
{
"_id" : ObjectId("51cd7274267d959cb9f95cea"),
"creation_time" : 100,
"delivered" : true,
"id" : 1,
"user_id" : 10
}
现在我想要的是每个用户的所有文档的\u id
(user\u id
),其中用户的文档数大于4。在跳过这4个文档之后,我还需要文档的\u id
。因此,如果一个用户有6个文档,那么我需要最后2个文档的\u id
(按创建时间排序),以便我可以将这2个旧文档归档到另一个数据库
我正在使用以下查询:
db.newsdb.aggregate([
{
$match: {
delivered: true
}
},
{
$group: {
_id: {
user_id: "$user_id",
creation_time: "$creation_time"
}
}
}
])
现在的问题是,我想对每个用户的文档执行$sort
和$skip
操作,而不是对所有用户的文档执行。所以我想要这样的东西:
{
$group: {
_id: {
user_id: "$user_id",
creation_time: "$creation_time"
}
},
$sort: {
user_id:1,
creation_time:1
},
$skip: 4
}
但mongo db似乎不支持它。我得到以下错误:
Error: Printing Stack Trace
at printStackTrace (src/mongo/shell/utils.js:37:7)
at DBCollection.aggregate (src/mongo/shell/collection.js:897:1)
at (shell):1:11
Mon Jul 1 14:47:55.762 JavaScript execution failed: aggregate failed: {
"errmsg" : "exception: A pipeline stage specification object must contain exactly one field.",
"code" : 16435,
"ok" : 0
} at src/mongo/shell/collection.js:L898
目前在聚合框架中无法做到这一点 您需要为每个用户进行单独的查询。您所能做的最好的事情是循环所有用户,为每个用户执行一个查询,以向您提供不是前4名的文档:
[user list].forEach(function(u) {
var listToArchive = db.newsdb.find({user_id: u},{_id:1}).sort({creation_time:-1}).skip(4);
/* do what you need to with listToArchive _id's */
} )
考虑太多之后,我想出了一个使用MapReduce的解决方案,因为使用聚合框架似乎是不可能的 下面是reduce函数,它通过
user\u id
对文档进行简单的分组
var mapf = function () {
emit(this.user_id, {
_id: this._id,
creation_time: this.creation_time
})
}
在reduce函数中,我检查是否至少有四个条目。如果为true,值
数组按创建时间
排序,并跳过前4个文档
var redf = function (key, values) {
var result = {};
if (values.length > 4) {
values.sort(function (a, b) {
return a.creation_time > b.creation_time;
});
// unfortunately, mongodb doesn't support array as result of reduce function
result['oids'] = values.slice(3);
}
return result;
}
现在是运行map-reduce命令的时候了。结果将插入到plus\u four\u用户
集合中
db.newsdb.mapReduce(mapf, redf, { out : "plus_four_users" })
这将导致如下结果:
> db.newsdb.find({}, { user_id : 1, creation_time : 1 })
{ "_id" : ObjectId("51d612423dab6225ca6e6d36"), "creation_time" : 100, "user_id" : 10 }
{ "_id" : ObjectId("51d612503dab6225ca6e6d37"), "creation_time" : 200, "user_id" : 10 }
{ "_id" : ObjectId("51d612553dab6225ca6e6d38"), "creation_time" : 300, "user_id" : 10 }
{ "_id" : ObjectId("51d612593dab6225ca6e6d39"), "creation_time" : 400, "user_id" : 10 }
{ "_id" : ObjectId("51d6125d3dab6225ca6e6d3a"), "creation_time" : 500, "user_id" : 10 }
{ "_id" : ObjectId("51d6126f55ebf2ff5a13d1c9"), "creation_time" : 600, "user_id" : 10 }
{ "_id" : ObjectId("51d6127455ebf2ff5a13d1ca"), "creation_time" : 300, "user_id" : 11 }
{ "_id" : ObjectId("51d6127955ebf2ff5a13d1cb"), "creation_time" : 400, "user_id" : 11 }
{ "_id" : ObjectId("51d6127c55ebf2ff5a13d1cc"), "creation_time" : 500, "user_id" : 11 }
{ "_id" : ObjectId("51d6127f55ebf2ff5a13d1cd"), "creation_time" : 600, "user_id" : 11 }
{ "_id" : ObjectId("51d6128555ebf2ff5a13d1ce"), "creation_time" : 700, "user_id" : 11 }
> db.plus_four_users.find().pretty()
{
"_id": 10,
"value": {
"oids": [
{
"_id": ObjectId("51d6125d3dab6225ca6e6d3a"),
"creation_time": 500
},
{
"_id": ObjectId("51d6126f55ebf2ff5a13d1c9"),
"creation_time": 600
}
]
}
}
{
"_id": 11,
"value": {
"oids": [
{
"_id": ObjectId("51d6128555ebf2ff5a13d1ce"),
"creation_time": 700
}
]
}
}
希望能对你有所帮助 为什么在
组中使用$ceation\u time
?难道许多文档不可能具有相同的用户id但创建时间不同吗?@Schaliasos如果我不使用$creation\u time
,那么它会将一个用户的所有文档分组在一行中。但是我希望所有的文档都是给一个用户的,这样我就可以对这些文档进行进一步的操作(排序和跳过)。现在的问题是,作为最终结果,这个分组的意义是什么。所以这个问题的答案是,我想对每个用户的所有文档执行排序
和跳过
,而不是对所有用户的所有文档执行。我想先通过user\u id
对它们进行分组,以便可以进行进一步的操作。如果你有更好的主意,你可以提出建议。那么也许你真的不需要组语句。哦,现在我明白了。尝试先对它们进行排序,然后对它们进行分组。先排序不会解决问题,因为group
操作会在排序之前忽略排序。确实可以使用map reduce完成此操作,但您的实现不正确。作为一个简单的测试,尝试使用一个示例数据集运行它,其中一个用户id恰好只有一个文档。它也不能在非常大的数据集上正常工作,而且它肯定会在碎片集合上崩溃。你是对的@AsyaKamsky。这个MR函数的问题是reduce函数缺少幂等性。事实上,Yatendra Goel做了一些moodifications并找到了解决方案,在这里可以找到:实际上我在这里给了他解决方案:它也可以用mapreduce完成,但可能是多个查询(如果索引)在整个集合上的速度将明显快于mapreduce。如果将四个要保留的文档嵌入到user_id对象中是有意义的,您可以利用2.4的功能来维护封顶数组—每个用户可以拥有包含四个最新文档的数组—这也简化了清理过程,因为在将较新文档插入其数组时会自动完成清理。