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.id
是current user
的ID
这个解决scheme是我以前的解决scheme稍微修改一个类似的问题在这里 。
有问题的文件有不一致的成员名称。 Martin Folwer
在整个应用程序/数据库中应该是Martin Fowler
,而不是Martin fowler
。 (注意小f
)。 您需要对文档进行更改。
-
$group
消息一起,根据来源和from
领域。 构造一个组密钥 – “message_between”,其值是$和/from
字段的$ concat结果。 -
从
Martin Fowler
到Jerry Jones
和Jerry Jones
到Martin Fowler
应该在一个单独的小组下进行处理。为了达到这个目的,我们首先要使结果包含最后按字母顺序排列的名字。 所以我们从Martin Fowler
到Jerry Jones
和Jerry Jones
到Martin 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也。