【问题标题】:Mongoose aggregation not returning latest document猫鼬聚合不返回最新文档
【发布时间】:2020-04-26 07:11:14
【问题描述】:

我有一个返回文档的聚合,但我需要它返回集合 messageTrackingId 中最新的文档。在creationDate 字段中具有最新值的那个我有一种方法可以完成此操作,但我不断收到不是最新的返回文档,我不知道为什么。目的是向用户显示该用户与另一个用户之间发送的最后一条消息的时间戳,无论是谁发送的。感谢任何帮助。

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

    Messages.aggregate([
      {
        $match: {
          $or: [
            { recipientId: req.query.recipientId },
            { creator: mongoose.Types.ObjectId(req.query.recipientId) }
          ]
        }
      },
      {
        $addFields: {
          conversant: {
            $cond: [
              { $ne: ["$recipientId", req.query.recipientId] },
              "$recipientId",
              "$creator"
            ]
          }
        }
      },
      {
        $sort: { creationDate: 1 }
      },
      {
        $group: {
          _id: "$conversant",
          message: { $last: "$message" },
          recipientId: { $last: "$recipientId" },
          creator: { $last: "$creator" },
          messageTrackingId: { $last: "$messageTrackingId" },
          recipient: { $last: "$recipient" },
          creationDate: { $last: "$creationDate" }
        }
      },
      {
        $lookup: {
          from: "users",
          let: { creator: "$creator" },
          pipeline: [
            { $match: { $expr: { $eq: ["$_id", "$$creator"] } } },
            { $project: { instagramName: 1 } }
          ],
          as: "creatorName"
        }
      }
    ]).then(documents => {


      if (inbox === true) {
        res.status(200).json({
          message: "User's Inbox Retrieved!",
          posts: documents
        });
      }

    });

我清理了消息表并来回发送了3条消息进行演示。当我重新加载页面时,我在 JSON 响应中只收到 2 个文档,而不是最新的一个。在收到的 2 个中,它们似乎都不是最新的。我不确定为什么它不返回一个。请参阅下面的页面加载输出。

消息:

/* 1 */
{
    "_id" : "5e16463be5fcba1d2c56ebb7",
    "creator" : "5e0a1d41f86e1e4234fc1a77",
    "recipient" : "andy",
    "recipientId" : "5df0014e25ee451beccf588a",
    "message" : "First message",
    "messageTrackingId" : "17c4fc99-d92f-46ef-9bae-1408f415287a",
    "creatorName" : "buyer1",
    "creationDate" : ISODate("2020-01-08T21:14:35.104Z"),
    "__v" : 0.0
}

/* 2 */
{
    "_id" : "5e16464de5fcba1d2c56ebb9",
    "creator" : "5df0014e25ee451beccf588a",
    "recipient" : "buyer1",
    "recipientId" : "5e0a1d41f86e1e4234fc1a77",
    "message" : "Second Message",
    "messageTrackingId" : "17c4fc99-d92f-46ef-9bae-1408f415287a",
    "creatorName" : "andy",
    "creationDate" : ISODate("2020-01-08T21:14:53.618Z"),
    "__v" : 0.0
}

/* 3 */
{
    "_id" : "5e16465ce5fcba1d2c56ebbb",
    "creator" : "5e0a1d41f86e1e4234fc1a77",
    "recipient" : "andy",
    "recipientId" : "5df0014e25ee451beccf588a",
    "message" : "Third Message",
    "messageTrackingId" : "17c4fc99-d92f-46ef-9bae-1408f415287a",
    "creatorName" : "buyer1",
    "creationDate" : ISODate("2020-01-08T21:15:08.500Z"),
    "__v" : 0.0
}

用户:

/* 1 */
{
    "_id" : "5df00d08c713f722909c99c1",
    "email" : "joe@gmail.com",
    "password" : "$2b$10$5eWhwL4RNT8TyQRCC191J.myYBwFcJ8hCARqGfofYWUmRaq6jJFQm",
    "instagramName" : "joe",
    "over21" : "Yes",
    "role" : "Artist",
    "fullName" : "testdsfdfsfs",
    "address1" : "adfsdf",
    "address2" : "dssdf",
    "city" : "sdfsdfsdf",
    "state" : "dsffsdsd",
    "zip" : "dsdfsdf",
    "passwordCreated" : ISODate("2020-01-07T23:46:57.861Z"),
    "__v" : 0
}

/* 2 */
{
    "_id" : "5df0014e25ee451beccf588a",
    "email" : "andy@gmail.com",
    "password" : "$2b$10$fNHmIoDb4mX6x.YeMLXHbu2yIaeW6HVQvNpZR8Nt/a4xVFkhxM1Ey",
    "instagramName" : "andy",
    "over21" : "Yes",
    "role" : "Artist",
    "fullName" : "dsfdsfdfdsf",
    "address1" : "111",
    "address2" : "111",
    "city" : "atlanta",
    "state" : "ga",
    "zip" : "33222",
    "passwordCreated" : ISODate("2019-12-19T15:29:46.528Z"),
    "__v" : 0
}

必需的输出(返回每个用户的最后一条消息):

/* 1 */
{
    "_id" : {
        "conversant" : "5df0014e25ee451beccf588a",
        "recipient" : "andy"
    },
    "message" : "Third Message",
    "recipientId" : "5df0014e25ee451beccf588a",
    "creator" : "5e0a1d41f86e1e4234fc1a77",
    "messageTrackingId" : "17c4fc99-d92f-46ef-9bae-1408f415287a",
    "recipient" : "andy",
    "creationDate" : ISODate("2020-01-08T21:15:08.500Z"),
    "creatorName" : [ 
        {
            "_id" : "5df0014e25ee451beccf588a",
            "instagramName" : "andy"
        }
    ]
}

/* 2 */
{
    "_id" : {
        "conversant" : "5df0014e25ee451beccf588a",
        "recipient" : "buyer1"
    },
    "message" : "Second Message",
    "recipientId" : "5e0a1d41f86e1e4234fc1a77",
    "creator" : "5df0014e25ee451beccf588a",
    "messageTrackingId" : "17c4fc99-d92f-46ef-9bae-1408f415287a",
    "recipient" : "buyer1",
    "creationDate" : ISODate("2020-01-08T21:14:53.618Z"),
    "creatorName" : [ 
        {
            "_id" : "5df0014e25ee451beccf588a",
            "instagramName" : "andy"
        }
    ]
}

【问题讨论】:

  • 我相信如果您提供示例文档和结果以便更好地了解正在发生的事情会更好,这是可以理解的,但如果有这些会更好
  • 参见上面的示例文档。我也做了一些修改
  • 如果我理解正确{ conversant: { $cond: [ { $ne: ["$recipientId", req.query.recipientId] }, "$recipientId", "$creator" ] } 在这个阶段你想在一个字段上按recipientId 分组(因为你不能为单个值分组两个字段)所以你正在创建一个新领域,是$ne 吗?我想应该是$eq!!
  • 我将 conversant 更新为 $eq 而不是 nq,当我刷新从 JSON 响应返回的第 2 页文档时,这 2 个文档都不是最新文档。
  • 我添加了-1,但问题仍然存在。这是我的代码的更新版本以供参考:pastebin.com/TWzxhELh

标签: node.js mongodb mongoose aggregation-framework


【解决方案1】:

改变必须是

1) 如果我在这个阶段理解正确,您想在一个字段上按 recipientId 分组(因为您不能对单个值的两个字段分组)所以您正在创建一个名为 conversant 的新字段, 所以它必须是$eq 或者你需要交换recipientId & creator & 也必须是$toString:

{
      $addFields: {
        conversant: {
          $cond: [
            { $eq: ["$recipientId", req.query.recipientId] },
            "$recipientId",
            {$toString : "$creator"} 
          ]
        }
      }
    }

2) 您不需要这个$sort 阶段,因为所有最新添加到集合的内容都将添加到最后(期望creationDate 已创建但从未更新):

// Not useful
{
     $sort: { creationDate: 1 }
}

您还需要按_id: { conversant: "$conversant", recipient: '$recipient' } 分组,以便根据user 对最后一条消息进行分组。在$lookup 中更改为let: { conversant: "$_id.conversant" }

试试这个:

 Messages.aggregate([
    {
        $match: {
            $or: [
                { recipientId: req.query.recipientId },
                { creator: mongoose.Types.ObjectId(req.query.recipientId) }
            ]
        }
    },
    {
        $addFields: {
            conversant: {
                $cond: [
                    { $eq: ["$recipientId", req.query.recipientId] },
                    "$recipientId",
                    { $toString: "$creator" }
                ]
            }
        }
    },
    {
        $group: {
            _id: { conversant: "$conversant", recipient: '$recipient' },
            message: { $last: "$message" },
            recipientId: { $last: "$recipientId" },
            creator: { $last: "$creator" },
            messageTrackingId: { $last: "$messageTrackingId" },
            recipient: { $last: "$recipient" },
            creationDate: { $last: "$creationDate" }
        }
    },
    {
        $lookup: {
            from: "users",
            let: { conversant: "$_id.conversant" },
            pipeline: [
                { $match: { $expr: { $eq: ["$_id", "$$conversant"] } } },
                { $project: { instagramName: 1 } }
            ],
            as: "creatorName"
        }
    },
     // this is optional only if you wanted to return latest document irrespective of user.
     { $sort: { creationDate: -1 } }
])

【讨论】:

  • 从我的测试来看,当用户发送消息时,他们现在拥有最新的文档,这很好,但收件人似乎在最新的
  • 我来回登录和退出每个用户帐户,最终它不会提取具有该 messageTracking Id 的最新文档。此表应具有最新日期 postimg.cc/Lh8wdLH5 ,但应显示 3:08:13 postimg.cc/p55BW2GG 而不是 3:07:49
猜你喜欢
  • 2018-08-22
  • 2017-03-30
  • 2015-08-04
  • 2018-07-10
  • 1970-01-01
  • 2016-05-24
  • 1970-01-01
  • 1970-01-01
  • 2016-02-02
相关资源
最近更新 更多