猫鼬:find() 忽略重复值 [英] Mongoose: find() ignore duplicate values

查看:55
本文介绍了猫鼬:find() 忽略重复值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个聊天"猫鼬 Schema,它具有以下属性:

const schema = mongoose.Schema({...接受者: {类型:猫鼬.Types.ObjectId,要求:真实,参考:'用户',},发件人:{类型:猫鼬.Types.ObjectId,要求:真实,参考:'用户',},内容: {类型:字符串,},...}, {时间戳:真实,});

通常,我想获取用户拥有的每个报道的最后一条消息.这意味着我需要提供一个用户 ID(可以存储在 senderrecipient 字段中)并取回最后一条消息(由 createdAt<表示)/code>) 用户与其他每个用户都有过.

示例:假设我有以下 documents:

[{收件人:一个",发件人:两个",createdAt: ISODate("2014-01-01T08:00:00Z"),},{收件人:一个",发件人:三",createdAt: ISODate("2014-02-15T08:00:00Z")},{收件人:两个",发件人:一个",createdAt: ISODate("2014-02-16T12:05:10Z")}]

插入One"作为输入 - Model.find(...) 的期望结果是:

[{收件人:一个",发件人:三",createdAt: ISODate("2014-02-15T08:00:00Z")},{收件人:两个",发件人:一个",createdAt: ISODate("2014-02-16T12:05:10Z")}]

解决方案

使用示例数据:

<预><代码>[{收件人:一个",发件人:两个",createdAt: ISODate("2014-01-01T08:00:00Z"),内容:一号先生你好!-二号"},{收件人:一个",发件人:三",createdAt: ISODate("2014-02-15T08:00:00Z"),内容:你好一!-三"},{收件人:两个",发件人:一个",createdAt: ISODate("2014-02-16T12:05:10Z"),内容:怎么了,二?-一"}]

查看以下聚合:https://mongoplayground.net/p/DTSDWX3aLWe

它...

  • 使用 $match 按收件人或发件人过滤所有邮件.返回匹配当前用户的那些 (One)
  • 使用包含 recipient$addFields 添加一个 conversationWith 字段,如果它是给用户 One 的消息或者 sender 如果是用户发送的消息
  • 使用 $sort
  • 按日期对邮件进行排序
  • 使用 $group 通过新的 conversationWith 字段对所有消息进行分组,并以 firstMessage
  • 形式返回最近的消息

完整的聚合管道:

db.collection.aggregate([{$匹配:{$和:[{$或:[{收件人:一个"},{发件人:一个"}],},]}},{$addFields:{对话:{$cond: {如果: {$eq: ["$sender",一"]},然后:$recipient",其他:$sender"}}}},{$排序:{创建于:-1}},{$组:{_id: "$conversationWith",第一条消息:{$first: "$$ROOT"}}}])

使用 mongoplayground,您可以一一删除聚合步骤,以查看每个步骤的作用.

试试:

  • $match步骤
  • $match + $addFields
  • $match + $addFields + $sort
  • [..]

为了最好的理解.

I have a "chat" mongoose Schema which has the following properties:

const schema = mongoose.Schema({
    ...
    recipient: {
        type: mongoose.Types.ObjectId,
        required: true,
        ref: 'User',
    },
    sender: {
        type: mongoose.Types.ObjectId,
        required: true,
        ref: 'User',
    },
    content: {
        type: String,
    },
    ...
}, {
    timestamps: true,
});

Generally, I want to fetch the last message of each coversation that a user has. Meaning that I need to provide a user id (that can be either stored in the sender or recipient field) and get back the last message (indicated by createdAt) the user had with each of the other users.

Example: Let's say I have the following documents:

[
  {
    recipient: "One",
    sender: "Two",
    createdAt: ISODate("2014-01-01T08:00:00Z"),

  },
  {
    recipient: "One",
    sender: "Three",
    createdAt: ISODate("2014-02-15T08:00:00Z")
  },
  {
    recipient: "Two",
    sender: "One",
    createdAt: ISODate("2014-02-16T12:05:10Z")
  }
]

Instering "One" as input - the desired result from Model.find(...) is:

[
  {
    recipient: "One",
    sender: "Three",
    createdAt: ISODate("2014-02-15T08:00:00Z")
  },
  {
    recipient: "Two",
    sender: "One",
    createdAt: ISODate("2014-02-16T12:05:10Z")
  }
]

解决方案

Using the example data:

[
  {
    recipient: "One",
    sender: "Two",
    createdAt: ISODate("2014-01-01T08:00:00Z"),
    content: "Hi Mr. One! - Two"
  },
  {
    recipient: "One",
    sender: "Three",
    createdAt: ISODate("2014-02-15T08:00:00Z"),
    content: "Hello One! - Three"
  },
  {
    recipient: "Two",
    sender: "One",
    createdAt: ISODate("2014-02-16T12:05:10Z"),
    content: "Whats up, Two? - One"
  }
]

Have a look at the following aggregation: https://mongoplayground.net/p/DTSDWX3aLWe

It...

  • Uses $match to filter all messages by recipient or sender. Returns the ones matching the current user (One)
  • Adds a conversationWith field using $addFields that contains the recipient if it is a message to user One or the sender if it is a message sent by user One
  • Sorts the messages by date using $sort
  • Groups all the messages using $group by the new conversationWith field and returns the most recent message as firstMessage

The full aggregation pipeline:

db.collection.aggregate([
  {
    $match: {
      $and: [
        {
          $or: [
            {
              recipient: "One"
            },
            {
              sender: "One"
            }
          ],

        },

      ]
    }
  },
  {
    $addFields: {
      conversationWith: {
        $cond: {
          if: {
            $eq: [
              "$sender",
              "One"
            ]
          },
          then: "$recipient",
          else: "$sender"
        }
      }
    }
  },
  {
    $sort: {
      createdAt: -1
    }
  },
  {
    $group: {
      _id: "$conversationWith",
      firstMessage: {
        $first: "$$ROOT"
      }
    }
  }
])

Using mongoplayground you can remove the aggregation steps one-by-one to see what each step does.

Try:

  • Only the $match step
  • $match + $addFields
  • $match + $addFields + $sort
  • [..]

for best understanding.

这篇关于猫鼬:find() 忽略重复值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆