【问题标题】:Returning unique mongodb documents using distinct not working使用不同的返回唯一的mongodb文档不起作用
【发布时间】:2019-11-17 23:50:43
【问题描述】:

每个消息文档都有一个 messageTrackingId。我想返回所有消息,但排除具有相同 messageTrackingId 的文档。例如,如果我的表中有 4 个文档,其中 3 个具有相同的 messageTrackingId 值,那么 Messages.find() 应该只返回 2 个文档。

我正在尝试使用 distinct 来仅返回唯一文档,这样我就不会得到具有相同 messageTrackingId 的重复文档。目前邮递员没有退回任何文件。

如果我改变了 Messages.find({query}).distinct('messageTrackingId')Messages.find(query) 然后它返回所有接收者 ID 的文档。但是当我添加 distinct 时,我没有得到任何结果。

app.get('/api/messages',(req, res, next)=>{
  query = {};
  inbox = false;
  messageId = false;
  if(req.query.recipientId){
    query = { recipientId: req.query.recipientId }
    inbox = true;

Messages.aggregate(// Pipeline
  [
      // Stage 1
      {
          $group: {
              _id: "$messageTrackingId",
              message : { $addToSet: '$message' },
              recipientId : { $addToSet: '$recipientId' },
              creator : { $addToSet: '$creator' },
              messageTrackingId : { $addToSet: '$messageTrackingId' },

          }
      },

      // Stage 2
      {
          $project: {
              _id: 1,
              message: { $arrayElemAt: ["$message", 0 ] },
              recipientId: { $arrayElemAt: ["$recipientId", 0 ] },
              creator: { $arrayElemAt: ["$creator", 0 ] },
              messageTrackingId: { $arrayElemAt: ["$messageTrackingId", 0 ] }
          }
      }

  ])

消息模型

const mongoose = require("mongoose");
const uniqueValidator = require("mongoose-unique-validator");

const messagingSchema = mongoose.Schema({
  creator: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
  recipient: { type: String, required: true },
  recipientId: { type: String, required: true },
  message: { type: String, required: true },
  subject: { type: String, required: true },
  creationDate: { type: Date, required: true },
  messageTrackingId: { type: String }
  // readDate: { type: Date, required: true }
});


module.exports = mongoose.model("Messages", messagingSchema);

【问题讨论】:

  • “如果我的表中有 4 个文档,其中 3 个具有相同的 messageTrackingId 值,那么 Messages.find() 应该只返回 2 个文档。” - 3 个中的哪一个应该被退回?
  • 只有 2 个文档会在该场景中返回,因为其中 3 个具有匹配的 messageTrackingId。我只需要每个 messageTrackingId 一个文档来引用该 messageTrackingID。
  • 那么如果5个文档都有相同的messageTrackingIds,只取第一个?按什么属性排序?
  • 排序没有偏好。只要其中一个返回,它使用相同的 messageTrackingId 抓取哪个文档都没有关系。当我为所有相关消息执行 GET 时,我只需要稍后引用该值。

标签: mongodb express mongoose


【解决方案1】:

distinct 将返回不同的 fields,这不是您想要的。

您需要使用 aggregation 并按 messageTrackingId 分组,然后项目抓取您想要的第一条消息内容等:

给定示例数据,例如:

{ "messageTrackingId" : 1, "message" : "hello" }
{ "messageTrackingId" : 1, "message" : "hello" }
{ "messageTrackingId" : 1, "message" : "bye" }
{ "messageTrackingId" : 2, "message" : "bye" }
{ "messageTrackingId" : 2, "message" : "bye" }
{ "messageTrackingId" : 1, "message" : "hello" }

在 MongoDB 中:

db.getCollection("messages").aggregate(

// Pipeline
[
    // Stage 1
    {
        $group: {
            _id: "$messageTrackingId",
            message : { $addToSet: '$message' }
        }
    },

    // Stage 2
    {
        $project: {
            _id: 1,
            message: { $arrayElemAt: ["$message", 0 ] }
        }
    },

]);

要在猫鼬中使用,只需在模型上使用 aggregate 函数:

使用猫鼬

const result = await Message.aggregate(// Pipeline
        [
            // Stage 1
            {
                $group: {
                    _id: "$messageTrackingId",
                    message : { $addToSet: '$message' }
                }
            },

            // Stage 2
            {
                $project: {
                    _id: 1,
                    message: { $arrayElemAt: ["$message", 0 ] }
                }
            },

        ]);

评论后更新

如果您需要查询给定的messageTrackingId,则添加$match 作为管道的第一阶段:

const result = await Message.aggregate(
        [
            {
                $match: {
                    messageTrackingId: {$eq: 2}
                }
            },
            {
                $group: {
                    _id: "$messageTrackingId",
                    message : { $addToSet: '$message' }
                }
            },
            {
                $project: {
                    _id: 1,
                    message: { $arrayElemAt: ["$message", 0 ] }
                }
            },

        ]);

【讨论】:

  • 我尝试将其添加到管道中,但我得到聚合不是函数?我究竟做错了什么?我更新了上面的代码
  • 有或没有 Messages.find(query) 我得到错误。如果我不添加该行,那么我看不到这将如何按收件人 ID 过滤消息以确保用户也收到他们自己的消息。我想我必须使用 $match 并且我在上面添加了额外的一行,但我还没有正确...
  • 该示例是为您在 MongoDB 中配置聚合查询。我已经更新了答案,向您展示如何简单地从您的模型中运行它。
  • 要在第一阶段添加匹配,在管道组之前使用以下内容:` { $match: { messageTrackingId: {$eq: 2} } },`
  • 我在组和项目中添加了另一行,我得到 messageTrackingId 现在返回。我只是不明白你为什么放 _id:"$messageTrackingId"?我更新了上面的代码
猜你喜欢
  • 2012-06-25
  • 2023-03-07
  • 1970-01-01
  • 2022-01-24
  • 2021-04-13
  • 1970-01-01
  • 2017-07-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多