【问题标题】:get count of conditionally matched elements from an array in MongoDB从 MongoDB 中的数组中获取条件匹配元素的计数
【发布时间】:2020-04-21 14:28:53
【问题描述】:

我想要今天日期的 cmets,它应该是非空的,以及通过使用 mongoose 它有多少 cmets。我已经尝试了很多。目前,我正在尝试用两种方法来实现。两者都有一些问题让我解释一下。请考虑我在 DB 中只有两个帖子,一个没有 cmets,例如:[],另一个有 2 个 cmets,其中两个包含今天的日期,3 个是旧的。

方法一:

在此方法中,它返回我今天的评论,但它只返回今天添加的单个评论。 并且还给我另一个没有 cmets 的对象

 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"}]}]

方法二: 在这种方法中,我在找到的对象中使用上面相同的东西,如下所示:

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

    res.send(doc);
  });

它返回给我所有 cmets(3 cmets)的第一个帖子,但不是第二个有空评论数组的帖子(很好)。

这是输出:

[{"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 }
);

所以,如果我总结了今天 cmets 所需的东西,今天是 4 月 21 日(两个 cmets),另一个评论日期是 20。我只需要今天的 cmets 及其计数。

如果我忘记了要添加的内容,请告诉我。谢谢

【问题讨论】:

    标签: node.js mongodb mongoose mongodb-query aggregation-framework


    【解决方案1】:

    有几个变化,$elemMatch 将只返回数组中的第一个匹配元素,而不是 comments 数组中的所有匹配元素。所以它在这里没有用,另外如果你今天想要 cmets,你需要使用 $gte 而不是 $gt 输入 startOfToday。最后,您需要使用aggregation-pipeline 来执行此操作:

    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

    【讨论】:

      猜你喜欢
      • 2016-01-12
      • 2015-06-21
      • 1970-01-01
      • 1970-01-01
      • 2011-03-11
      • 2021-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多