Mongodb 按两个交换字段分组的查询

Mongodb 按两个交换字段分组的查询,mongodb,mongoid,Mongodb,Mongoid,我收集了信息和以下文档 { "_id" : ObjectId("5164218f359f109fd4000012"), "receiver_id" : ObjectId("5164211e359f109fd4000004"), "sender_id" : ObjectId("5162de8a359f10cbf700000c"), "body" : "Hello Billy!!!", "readed" : false, "updated_at" : ISODate("201

我收集了
信息
和以下文档

{
  "_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")
}
我需要为给定用户(按接收者id+发送者id字段分组)查询receive last messages(无论是Received还是Send),并按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解决这个问题。

没有明确的方法。让我们回顾一下解决方法:

方式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\u id,receiver\u id
sender\u id+receiver\u id


方法3:引入代理字段发送者id+接收者id,然后根据Stennie提示使用
find
甚至
distinct

没有明确的方法。让我们回顾一下解决方法:

方式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\u id,receiver\u id
sender\u id+receiver\u id

方法3:引入代理字段sender\u id+receiver\u id,然后根据Stennie提示使用
find
甚至
distinct

在MongoDB 2.2+中提供了最明显的查询翻译。MongoDB手册包括一个通用指南,尽管这两种方法有明确的区别

下面是一个注释示例,您可以在
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
}
您可能希望在分组中添加其他字段,例如接收的邮件数

如果您确实想将发送者id+接收者id组合到一个字段中,您可以使用MongoDB 2.4+中的运算符。

MongoDB 2.2+中的运算符提供了最明显的查询翻译。MongoDB手册包括一个通用指南,尽管这两种方法有明确的区别

下面是一个注释示例,您可以在
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
}
您可能希望在分组中添加其他字段,例如接收的邮件数


如果您确实想将发送者id+接收者id组合到一个字段中,您可以使用MongoDB 2.4+中的运算符。

与您的方式#3和代理字段一起使用,您实际上可以在该字段上使用命令,而不是使用
find()
.way#2和
$group:{id:{sender:$sender#id],receiver:$receiver#id}
似乎不起作用,因为当交换字段时,其结果是make new entity。@ole-您不需要交换字段,因此即使sender为null,那么键也将是相同的
{null,ObjectId(“5164211e359f109fd4000004”)}
通过您的方式#3和代理字段,您实际上可以在该字段上使用命令,而不是
find()
.Way#2 with
$group:{sender:$sender:$sender\u id,receiver:$receiver\u id”}
似乎不起作用,因为在交换字段时,其结果是生成新实体。@ole-您不需要交换字段,所以即使sender为null,键也将是相同的
{null,ObjectId(“5164211e359f109fd4000004”)}
在给定的情况下,用户不仅要发送,还要接收一些消息。组无法按需要工作,因为给定用户的字段(发送者id、接收者id)已交换,并且结果中出现了新实体。因此,我在SQL中使用了
发送者id+接收者id
。如果您将给定用户匹配为
发送者id
接收者id
,这将涵盖该用户发送或接收消息的情况,应该与您的SQL查询等效。分组输出将区分相同两个用户交换电子邮件的情况:
{sender\u id:user1,receiver\u id:user2}
vs`{sender\u id:user2,receiver\u id:user1}。如果您确实想要唯一对,那么您的SQL查询也需要更改。我的SQL示例工作正常,因为在SQL中id是整数。无论如何,感谢您提供了一个帮助我理解一些事情的好解决方案。顺便问一下,如果我将结构更改为嵌入式
用户:{sender_id:“5162de8a359f10cbf70000c”,receiver_id:“5162de8a359f10cbf7000004”}
,您认为如何。这对我有帮助吗?在…中为用户指定了带有复选框的mb,例如
。在指定的情况下,用户不仅发送消息,还接收一些消息。组无法按需要工作,因为给定用户的字段(发送者id、接收者id)已交换,并且结果中出现了新实体。因此,我在SQL中使用了
发送者id+接收者id
。如果您将给定用户匹配为
发送者id
接收者id
,这将涵盖该用户发送或接收消息的情况,应该与您的SQL查询等效。分组输出将区分相同两个用户交换电子邮件的情况:
{sender\u id:user1,receiver\u id:user2}
vs`{sender\u id:user2,receiver\u id:user1}。如果您确实想要唯一对,那么您的SQL查询也需要更改。我的SQL示例工作正常,因为在SQL中id是整数。无论如何,感谢您提供了一个帮助我理解一些事情的好解决方案。顺便问一下,如果我将结构更改为嵌入式
用户:{sender_id:“5162de8a359f10cbf70000c”,receiver_id:“5162de8a359f10cbf7000004”}
,您认为如何。这对我有帮助吗?在…
中为用户提供了带有类似于
的复选框的mb。