Как мне вернуть только НЕКОТОРЫЕ поля ($ project) из агрегации Mongodb, одновременно используя $ match, $ lookup AND $ filter - PullRequest
0 голосов
/ 28 мая 2020

Я ОЧЕНЬ близок к тому, чтобы получить то, что я хочу от этого запроса ... но я хочу, чтобы возвращались только НЕКОТОРЫЕ поля, и прямо сейчас он возвращает их все

ПРИМЕЧАНИЕ : Это уточнение: теперь я спрашиваю, как вернуть только определенные поля , в то время как мой аналогичный вопрос спрашивает, как вернуть данные между датой начала и окончания

Кроме того, может кто-нибудь, пожалуйста, предоставьте ответ, используя 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
                    },
            }}
        };

РЕШЕНИЕ

Я создал еще одну проекцию и добавил ее в конвейер: * 10 55 *

        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,
        ];

Спасибо !!

Ответы [ 2 ]

0 голосов
/ 28 мая 2020

Вам нужно преобразовать notifications.dateCreated в ISODate, поскольку ваша дата находится в строке, используя операторы $dateFromString и $map. Я предлагаю вам сделать это, потому что я не думаю, что вы можете сравнивать даты со строковыми форматами. Также убедитесь, что dateStart и dateEnd также должны быть в формате 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

0 голосов
/ 28 мая 2020

{ ссылка } было правильным.

Я создал еще одну проекцию:

        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,
        ];

Сработало! - спасибо { ссылка }

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...