查询按两个交换字段分组

时间:2013-04-09 15:15:27

标签: mongodb mongoid

我的收藏集messages包含以下文件

{
  "_id" : ObjectId("5164218f359f109fd4000012"),
  "receiver_id" : ObjectId("5164211e359f109fd4000004"),
  "sender_id" : ObjectId("5162de8a359f10cbf700000c"),
  "body" : "Hello Billy!!!",
  "readed" : false,
  "updated_at" : ISODate("2013-04-09T14:11:27.17Z"),
  "created_at" : ISODate("2013-04-09T14:11:27.17Z")
}

我需要查询接收给定用户的最后消息(无论是收到的还是已发送的)(按reciever_id + sender_id字段分组)并按created_at排序。

为了更好地解释这个问题,我在SQL中如何做到这一点的一个例子:

SELECT DISTINCT ON (sender_id+receiver_id) * FROM messages 
    ORDER by (sender_id+receiver_id), created_at DESC
    WHERE sender_id = given_user or receiver_id = given_user 

我不明白如何用mondodb来解决这个问题。

2 个答案:

答案 0 :(得分:2)

MongoDB 2.2+中的Aggregation Framework提供了最明显的查询翻译。 MongoDB手册包含SQL to Aggregation Framework Mapping Chart作为一般指南,尽管这两种方法存在明显差异。

以下是您可以在mongo shell中尝试的注释示例:

var given_user = ObjectId("5162de8a359f10cbf700000c");
db.messages.aggregate(
    // match: WHERE sender_id = given_user or receiver_id = given_user
    // NB: do the match first, because it can take advantage of an available index
    { $match: {
        $or:[
            { sender_id: given_user },
            { receiver_id: given_user },
        ]
    }},

    { $group: {
        //  DISTINCT ON (sender_id+receiver_id)
        _id: { sender_id: "$sender_id", receiver_id: "$receiver_id" }
    }},

    // ORDER by (sender_id+receiver_id), created_at DESC
    { $sort: {
        sender_id: 1,
        receiver_id: 1,
        created_at: -1
    }}
)

示例结果:

{
    "result" : [
        {
            "_id" : {
                "sender_id" : ObjectId("5162de8a359f10cbf700000c"),
                "receiver_id" : ObjectId("5164211e359f109fd4000004")
            }
        }
    ],
    "ok" : 1
}

您可能希望在分组上添加其他字段,例如收到的消息数。

如果您确实想将sender_id + receiver_id组合到一个字段中,可以使用MongoDB 2.4 +中的$concat运算符。

答案 1 :(得分:1)

没有明确的方法可以这样做。让我们回顾一下解决方法:

方式1: 在代码级别执行distinct(在查找之后),然后使用find

db.message.find({$or:[{sender_id:?}, {receiver_id:?}]})

方式2:使用聚合框架:

db.message.aggregate( [
   {$match: {$or:[{sender_id:?}, {receiver_id:?}]},
    $group: { _id: {sender:"$sender_id", receiver:"$receiver_id"},
               other: { ... } } },
   $sort: {sender_id,receiver_id,...}
   ] ) 

这种问题出现在排序级别,因为sender_id, receiver_idsender_id+receiver_id

不同

方式3:介绍代理字段sender_id + receiver_id,然后根据Stennie提示使用find甚至distinct