Mongo查询和响应“GroupBy”实现使用Mongoose和/或underscore.js

我们有以下格式的mongo收集messages

 /* 0 */ { "text" : "A message to John", "created" : ISODate("2015-01-29T23:50:10.488Z"), "to" : { "id" : ObjectId("54bf1dc6c65b030c00faec0d"), "name" : "John Smith" }, "from" : { "id" : ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name" : "Martin Fowler" }, } /* 1 */ { "text" : "Another message to John", "created" : ISODate("2015-01-30T00:37:38.106Z"), "to" : { "id" : ObjectId("54bf1dc6c65b030c00faec0d"), "name" : "John Smith" }, "from" : { "id" : ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name" : "Martin fowler" }, } /* 2 */ { "text" : "Just another message to Jerry", "created" : ISODate("2015-01-30T00:37:38.106Z"), "to" : { "id" : ObjectId("54bf1e80eb5bf8800b0f5a8d"), "name" : "Jerry Jones" }, "from" : { "id" : ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name" : "Martin Fowler" }, } /* 2 */ { "text" : "Message to Martin Fowler", "created" : ISODate("2015-01-30T00:37:38.106Z"), "to" : { "id" : ObjectId("54bf1e80eb5bf8800b0f5a8d"), "name" : "Martin Fowler" }, "from" : { "id" : ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name" : "Jerry Jones" }, } 

我们需要以对话格式显示上面的数据,并将每个对话分组在一起。 谈话的意思,它可以是或from

我们需要这个数据的例子是以下格式:

 { "result":[ { "id":"54bf1dc6c65b030c00faec0d", "name":"Jerry Jones", "messages":[ { "text" : "A message to John", "created" : ISODate("2015-01-29T23:50:10.488Z"), "to" : { "id" : ObjectId("54bf1dc6c65b030c00faec0d"), "name" : "John Smith" }, "from" : { "id" : ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name" : "Martin Fowler" }, } { "text" : "Another message to John", "created" : ISODate("2015-01-30T00:37:38.106Z"), "to" : { "id" : ObjectId("54bf1dc6c65b030c00faec0d"), "name" : "John Smith" }, "from" : { "id" : ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name" : "Martin fowler" }, } ] }, { "id":"54bf1e80eb5bf8800b0f5a8d", "name":"John Smith", "messages":[ { "text" : "Just another message to Jerry", "created" : ISODate("2015-01-30T00:37:38.106Z"), "to" : { "id" : ObjectId("54bf1e80eb5bf8800b0f5a8d"), "name" : "Jerry Jones" }, "from" : { "id" : ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name" : "Martin Fowler" }, } { "text" : "Message to Martin Fowler", "created" : ISODate("2015-01-30T00:37:38.106Z"), "to" : { "id" : ObjectId("54bf1e80eb5bf8800b0f5a8d"), "name" : "Martin Fowler" }, "from" : { "id" : ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name" : "Jerry Jones" }, } ] } ] } 

注意这个查询总是在current user的上下文中进行的,这就是为什么在每个对话中,我们都有一个_id和一个代表对话中另一个用户的name 。 对于上面的例子, current user将是Martin Fowler

我们已经尝试了几种不同的方法来完成这个任务,但是仍然遇到问题。 而是转向Mongo / Node社区,以了解如何正确完成。 我们正在与节点使用mongoose ,如果有所帮助…

我们目前的初始查询实现如下:

 Message.find().or([{'from.id':req.user.id},{'to.id':req.user.id}]).exec(function(err,messages){ //NEED TO IMPLEMENT THIS HERE CORRECTLY }); 

请注意req.user.idcurrent user的ID

这个解决scheme是我以前的解决scheme稍微修改一个类似的问题在这里 。

有问题的文件有不一致的成员名称。 Martin Folwer在整个应用程序/数据库中应该是Martin Fowler ,而不是Martin fowler 。 (注意小f )。 您需要对文档进行更改。

  • $group消息一起,根据来源和from领域。 构造一个组密钥 – “message_between”,其值是$和/ from字段的$ concat结果。

  • Martin FowlerJerry JonesJerry JonesMartin Fowler应该在一个单独的小组下进行处理。为了达到这个目的,我们首先要使结果包含最后按字母顺序排列的名字。 所以我们从Martin FowlerJerry JonesJerry JonesMartin Fowler所有信息的关键是Martin Fowler and Jerry Jones

码:

 Model.aggregate( //match all those records which involve the user. {$match:{$or:[{"to.name":req.user.id}, {"from.name":req.user.id}]}}, {$group:{"_id":{ "message_between":{ $cond:[ { $gt:[ {$substr:["$to.name",0,1]}, {$substr:["$from.name",0,1]}] }, {$concat:["$to.name"," and ","$from.name"]}, {$concat:["$from.name"," and ","$to.name"]} ] },"name":{$cond:[{$eq:["$to.name", req.user.id]}, "$from.name", "$to.name"]} },"messages":{$push:"$$ROOT"} } }, {$project:{"_id":0,"name":"$_id.name","messages":1}} ,function(err,resp){ // handle response. }) 

O / P:

 { "messages" : [ { "_id" : ObjectId("54d1d819b62f332e93fbb906"), "text" : "Just another message to Jerry", "created" : ISODate("2015-01-30T00:37:38.106Z"), "to" : { "id" : ObjectId("54bf1e80eb5bf8800b0f5a8d"), "name" : "Jerry Jones" }, "from" : { "id" : ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name" : "Martin Fowler" } }, { "_id" : ObjectId("54d1d819b62f332e93fbb907"), "text" : "Message to Martin Fowler", "created" : ISODate("2015-01-30T00:37:38.106Z"), "to" : { "id" : ObjectId("54bf1e80eb5bf8800b0f5a8d"), "name" : "Martin Fowler" }, "from" : { "id" : ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name" : "Jerry Jones" } } ], "name" : "Jerry Jones" } { "messages" : [ { "_id" : ObjectId("54d1d819b62f332e93fbb904"), "text" : "A message to John", "created" : ISODate("2015-01-29T23:50:10.488Z"), "to" : { "id" : ObjectId("54bf1dc6c65b030c00faec0d"), "name" : "John Smith" }, "from" : { "id" : ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name" : "Martin Fowler" } }, { "_id" : ObjectId("54d1d819b62f332e93fbb905"), "text" : "Another message to John", "created" : ISODate("2015-01-30T00:37:38.106Z"), "to" : { "id" : ObjectId("54bf1dc6c65b030c00faec0d"), "name" : "John Smith" }, "from" : { "id" : ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name" : "Martin Fowler" } } ], "name" : "John Smith" } 

我试图为你创build一个mongo请求,但我不确定它是否相关…我可以在一个请求中生成几乎完全相同的格式:

 db.messages.aggregate([{$match:{$or:[{"from.id":ObjectId("54bf1dc6c65b030c00faec0d")},{"to.id":ObjectId("54bf1dc6c65b030c00faec0d")}]}},{$group:{_id: ObjectId("54bf1dc6c65b030c00faec0d"), messages:{$push: "$$ROOT"}}}]); 

问题是,你仍然需要指定的ID,我不知道这是你所需要的。

使用这个我得到以下结果:

 { "_id": ObjectId("54bf1dc6c65b030c00faec0d"), "messages": [ { "_id": ObjectId("54d1b9f02cd45cae7e453633"), "text": "A message to John", "created": ISODate("2015-01-29T23:50:10.488Z"), "to": { "id": ObjectId("54bf1dc6c65b030c00faec0d"), "name": "John Smith" }, "from": { "id": ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name": "Martin Fowler" } }, { "_id": ObjectId("54d1ba052cd45cae7e453634"), "text": "Another message to John", "created": ISODate("2015-01-30T00:37:38.106Z"), "to": { "id": ObjectId("54bf1dc6c65b030c00faec0d"), "name": "John Smith" }, "from": { "id": ObjectId("54bf1e1ceb5bf8800b0f5a8c"), "name": "Martin fowler" } } ] } 

我没有使用mongoose,所以我不能帮你这个部分,但与“mongodb”模块,这个查询可以直接使用,所以它应该可能与mongoose也。