получить количество условно сопоставленных элементов из массива в MongoDB - PullRequest
2 голосов
/ 21 апреля 2020

Мне нужны комментарии с сегодняшней датой, и они должны быть непустыми, и сколько комментариев они имеют, используя mon goose. Я много пробовал. В настоящее время я пытаюсь достичь двумя способами. у обоих есть некоторые проблемы, позвольте мне объяснить. пожалуйста, учтите, что у меня только две записи в БД, одна из которых не имеет комментариев типа: [], а другая имеет 2 комментария, два из которых содержат дату сегодня, а 3 - старое.

Метод 1:

в этом методе он возвращает мне комментарий сегодня, но он возвращает только один комментарий, добавленный сегодня. а также возвращая мне другой объект, который не имеет комментариев

 Post.find({ })
    .select({
      comments: { $elemMatch: { date: { $gt: startOfToday } }  },
      title: 1,
    })
    .exec((err, doc) => {
      if (err) return res.status(400).send(err);

      res.send(doc);
    });

, результат вышеприведенного кода:

[{"_id":"5e9c67f0dd8479634ca255b1","title":"sdasd","comments":[]},{"_id":"5e9d90b4a7008d7bf0c4c96a","title":"sdsd","comments":[{"date":"2020-04-21T04:04:11.058Z","votes":
[{"user":"hhhh","vote":1}],"_id":"5e9e70bbece9c31b33f55041","author":"hhhh","body":"xvxgdggd"}]}]

Метод 2: В этом методе я использую то же самое выше внутри найденного объекта, например:

 Post.find({ comments: { $elemMatch: { date: { $gt: startOfToday } } } })
  .exec((err, doc) => {
    if (err) return res.status(400).send(err);

    res.send(doc);
  });

И он возвращает мне первое сообщение со всеми комментариями (3 комментария), но не второе сообщение (это хорошо), которые имеют пустой массив комментариев.

вот вывод:

[{"author":{"id":"5e85b42f5e4cb472beedbebb","nickname":"hhhh"},"hidden":false,"_id":"5e9d90b4a7008d7bf0c4c96a","title":"sdsd","body":"dsfdsfdsf","votes":[{"user":"5e85b42f5e4cb472beedbebb","vote":1}],"comments":[{"date":"2020-04-20T12:08:32.585Z","votes":[],"_id":"5e9d90c0a7008d7bf0c4c96b","author":"hhhh","body":"zcxzczxc z zxc"},
{"date":"2020-04-21T04:04:11.058Z","votes":[{"user":"hhhh","vote":1}],"_id":"5e9e70bbece9c31b33f55041","author":"hhhh","body":"xvxgdggd"},
{"date":"2020-04-21T04:56:25.992Z","votes":[],"_id":"5e9e7cf96095882e11dc510c","author":"hhhh","body":"new should appear in feeds"}],"date":"2020-04-20T12:08:20.687Z","createdAt":"2020-04-20T12:08:20.692Z","updatedAt":"2020-04-21T04:56:26.003Z","__v":3}]

Это моя схема сообщений:

  const postSchema = new Schema(
  {
    title: {
      type: String,
      required: true,
      unique: 1,
      index: true,
    },
    author: {
      id: {
        type: mongoose.Schema.Types.ObjectId,
        ref: "User",
      },
      nickname: String,
    },
    body: {
      type: String,
      required: true,
    },
    comments: [
      {
        author: {
          type: String,
          required: true,
        },
        body: {
          type: String,
          required: true,
        },
        date: { type: Date, default: Date.now },
        votes: [{ user: String, vote: Number, _id: false }],
      },
    ],
    date: { type: Date, default: Date.now },
    hidden: {
      type: Boolean,
      default: false,
    },
    votes: [{ user: Schema.Types.ObjectId, vote: Number, _id: false }],
  },
  { timestamps: true }
);

Итак, если у меня есть СУММА, что мне нужно, сегодняшние комментарии, а сегодня 21 апреля (два комментария) и еще одна дата комментариев - 20. Мне нужны только сегодняшние комментарии с их количеством.

Если я забыл что-то добавить, пожалуйста, дайте мне знать. Спасибо

1 Ответ

1 голос
/ 21 апреля 2020

Есть несколько изменений, так как $ elemMatch вернет только первый соответствующий элемент из массива, но не все соответствующие элементы в массиве comments. Так что здесь это бесполезно, кроме того, если вам нужны комментарии на сегодня, вам нужно использовать $gte вместо $gt для ввода startOfToday. Наконец, вам нужно использовать агрегационный конвейер , чтобы сделать это:

db.collection.aggregate([
   /** Lessen the no.of docs for further stages by filter with condition */
  {
    $match: { "comments.date": { $gte: ISODate("2020-04-21T00:00:00.000Z") } }
  },
  /** Re-create `comments` array by using filter operator with condition to retain only matched elements */
  {
    $addFields: {
      comments: {
        $filter: {
          input: "$comments",
          cond: { $gte: ["$$this.date", ISODate("2020-04-21T00:00:00.000Z")] }
        }
      }
    }
  },
  {
    $addFields: { count: { $size: "$comments" } } // Add count field which is size of newly created `comments` array(Which has only matched elements)
  }
]);

Тест: mongoplayground

...