【问题标题】:How do I only return SOME fields ($project) from Mongodb aggregation, while also using $match, $lookup AND $filter我如何只从 Mongodb 聚合中返回一些字段($project),同时还使用 $match、$lookup 和 $filter
【发布时间】:2020-09-15 20:31:10
【问题描述】:

我非常接近从这个查询中得到我想要的东西......但我只想要返回一些字段,现在它正在返回所有这些字段

注意:这是一个改进:我现在询问如何返回仅某些字段,而我类似的 question 询问如何返回开始日期和结束日期之间的数据

另外,请有人使用MongoDB Playground 和我的数据集提供答案,以便我可以尝试一下...我不太清楚如何“命名”数据集以便它们工作操场 !

注册架构

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const RegisterSchema = new Schema({
    userId: {type: Schema.Types.ObjectId, required: true},
    accessToken: {type:String, required: true, default: null},
})
module.exports = Register = mongoose.model( 'register', RegisterSchema)

这是一些寄存器数据

[
  {
    "_id": "5eac9e815fc57b07f5d0d29f",
    "userId": "5ea108babb65b800172b11be",
    "accessToken": "111"
  },
  {
    "_id": "5ecaeba3c7b910d3276df839",
    "userId": "5e6c2dddad72870c84f8476b",
    "accessToken": "222"
  }
]

下一个文档包含通过 accessToken 与注册模式相关的数据

通知

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const NotificationSchema = new Schema({
    accessToken: {type:String, required: true},
    summaryId: {type:Number, required: true},
    dateCreated: {type: Date, default: Date.now},

    // I don't want these returned in the final results
    dontWantThis1: {type:Number, required: true},
    dontWantThis2: {type:Number, required: true},
})
module.exports = Notification = mongoose.model( 'notification', NotificationSchema)

这是一些通知数据

[{
    "_id": "5ebf0390c719e60004f42e74",
    "accessToken": "111",
    "summaryId": 1111,
    "dontWantThis1": 61,
    "dontWantThis2": 62,
    "dateCreated": "2020-04-17T00:00:00.000+00:00" }, 
  {
    "_id": "6ebf0390c719e60004f42e76",
    "accessToken": "222",
    "summaryId": 2221,
    "dontWantThis1": 71,
    "dontWantThis2": 72,
    "dateCreated": "2020-04-18T00:00:00.000+00:00" },
  {
    "_id": "6ebf0390c719e60004f42e78",
    "accessToken": "111",
    "summaryId": 1112,
    "dontWantThis1": 611,
    "dontWantThis2": 622,
    "dateCreated": "2020-05-25T00:00:00.000+00:00" },
  {
    "_id": "6ebf0390c719e60004f42e80",
    "accessToken": "222",
    "summaryId": 2222,
    "dontWantThis1": 711,
    "dontWantThis2": 722,
    "dateCreated": "2020-05-26T00:00:00.000+00:00" }
]

有效,返回两个日期之间的数据,但是

此代码返回所有内容,包括“dontWantThis1”和“dontWantThis2”

注意

我不想要以“dontWantThis”开头的字段 - 但这只是为了显示我不想要的字段……我不想排除以“dontWantThis”开头的字段' ..... 它们可以被命名为 'foo' 或 'apple' 或 'dog' 他们只是这样命名以表明我不想要它们


        // make sure the input dates are REALLY date objects
        // I only want to see notifications for the month of May (in this example)
        var dateStart = new Date('2020-05-01T00:00:00.000+00:00');
        var dateEnd = new Date('2020-05-30T00:00:00.000+00:00');     

        var match = {$match: { userId: mongoose.Types.ObjectId(userId) } };

        var lookup ={
            $lookup:
            {
                from: "my_Notifications",
                localField: "accessToken",
                foreignField: "accessToken",
                as: "notifications"
            }
        };

        var dateCondition = { $and: [
            { $gte: [ "$$item.dateCreated", dateStart ] },
            { $lte: [ "$$item.dateCreated", dateEnd ] }
          ]}  

        var project = {
            $project: {
                notifications: {
                    $filter: {
                    input: "$notifications",
                    as: "item",
                    cond: dateCondition
                    } } }
        };

        var agg = [
            match,
            lookup,
            project
        ];

        Register.aggregate(agg)
        .then( ..... )

试试 1

我以为我可以做这样的事情,但它仍然返回所有通知字段

        var project = {
            $project: {
                "_id": 1,
                "userId": 1,
                "accessToken":1,
                "count":{$size:"$notifications"},
                "notifications._id":1,
                "notifications.summaryId": 1,
                "notifications.dateCreated":1,

                notifications : {
                    $filter: {
                    input: "$notifications",
                    as: "item",
                    cond: dateCondition
                    },
            }}
        };

解决方案

我创建了另一个投影并将其添加到管道中:

        var project2 = {
            $project: {
                "_id": 1,
                "userId": 1,
                "accessToken":1,
                "count":{$size:"$notifications"},
                "notifications._id":1,
                "notifications.summaryId": 1,
                "notifications.dateCreated":1,
                "notifications.dateProcessed":1,
            }
        };


        var agg = [
            match,
            lookup,
            project,
            project2,
        ];

谢谢!!

【问题讨论】:

标签: mongodb filtering lookup aggregation projection


【解决方案1】:

https://stackoverflow.com/users/6635464/ngshravil-py 出现在现场。

我创建了另一个投影:

        var project2 = {
            $project: {
                "_id": 1,
                "userId": 1,
                "accessToken":1,
                "count":{$size:"$notifications"},
                "notifications._id":1,
                "notifications.summaryId": 1,
                "notifications.dateCreated":1,
                "notifications.dateProcessed":1,
            }
        };

然后将其添加到我的聚合管道中:

        var agg = [
            match,
            lookup,
            project,
            project2,
        ];

工作! -- 谢谢https://stackoverflow.com/users/6635464/ngshravil-py

【讨论】:

    【解决方案2】:

    您需要使用$dateFromString$map 运算符将notifications.dateCreated 转换为ISODate,因为您的日期是字符串。我建议你这样做,因为我认为你不能用字符串格式进行日期比较。另外,请确保dateStartdateEnd 也应采用ISODate 格式。

    您需要两个$project 运算符才能实现这一点。另外,我没有看到任何带有userAccessToken 的字段,我认为它是accessToken。检查以下查询。

    db.Register.aggregate([
      {
        $lookup: {
          from: "my_Notifications",
          localField: "accessToken",
          foreignField: "accessToken",
          as: "notifications"
        }
      },
      {
        $project: {
          "_id": 1,
          "userId": 1,
          "accessToken": 1,
          notifications: {
            $map: {
              input: "$notifications",
              as: "n",
              in: {
                "_id": "$$n._id",
                "summaryId": "$$n.summaryId",
                "dateCreated": {
                  $dateFromString: {
                    dateString: "$$n.dateCreated"
                  }
                }
              }
            }
          }
        }
      },
      {
        $project: {
          "userId": 1,
          "accessToken": 1,
          "notifications": {
            $filter: {
              input: "$notifications",
              as: "item",
              cond: {
                $and: [
                  {
                    $gte: [
                      "$$item.dateCreated",
                      ISODate("2020-05-24T00:00:00Z")
                    ]
                  },
                  {
                    $lte: [
                      "$$item.dateCreated",
                      ISODate("2020-05-26T00:00:00Z")
                    ]
                  }
                ]
              }
            }
          }
        }
      },
      {
        $set: {
          "count": {
            $size: "$notifications"
          }
        }
      }
    ])
    

    MongoPlayGroundLink

    【讨论】:

    • 很酷...但是计数不正确...计数显示2,当只有1个通知时? (检查操场输出)
    • @MLissCetrus,感谢您让我知道,有点想念。我已经更新了我的答案。 :)
    猜你喜欢
    • 2020-09-18
    • 2020-08-07
    • 1970-01-01
    • 1970-01-01
    • 2013-03-10
    • 2019-11-08
    • 2021-04-11
    • 2015-12-03
    • 1970-01-01
    相关资源
    最近更新 更多