2

I want comments with today's date and it should be non-empty and how much comments it has via using mongoose. I have tried a lot. Currently, I am trying to achieve with two methods. both have some problems let me explain. please consider I have only two posts in DB one has no comments like: [], and the other has 2 comments two inside it with today date and the 3 is old.

Method 1 :

in this method, it returns me today comment but it only returns single comment added on today. and also returning me another object which has no comments

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

      res.send(doc);
    });

the output of above code is :

[{"_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"}]}]

Method 2 : In this method I am using the same thing above inside the found object like this:

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

    res.send(doc);
  });

And it returns me first post with all comments (3 comments) but not second post(that is good) that have empty comment array.

here is the output :

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

This is my post schema :

  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 }
);

So, if I have SUM up the things I need today comments and today is 21st April (Two comments) and another comment date is 20. I only need today's comments with its count.

If I forgot something to add please let me know. Thanks

1 Answer 1

1

There are couple of changes as $elemMatch would return only the first matching element from array but not all the matching elements in comments array. So it's not useful here, additionally if you want comments for today you need to use $gte instead of $gt for input startOfToday. Finally, You need to use aggregation-pipeline to do this :

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)
  }
]);

Test : mongoplayground

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.