Reputation: 590
I have the following issue. I have some comments that are soft-deletable. So they have a flag is_deleted
and it is set to true when a record is deleted.
My comments aren't an independent model, but they are a nested array in another model (simplified model):
let CommentSchema = new Schema({
text: {
type: String,
required: true
},
modified_at: {
type: Date,
default: null
},
created_at: {
type: Date,
default: Date.now
},
is_deleted: {
type: Boolean,
default: false
},
});
let BookSchema = new Schema({
...
comments: [CommentSchema],
...
});
Now when I get all my Books with Books.find({}, (err, books) => {})
I wanted to filter out the deleted comments in:
BookSchema.pre('find', function() {
this.aggregate(
{},
{ $unwind: '$comments'},
{ $match: {'comments.is_deleted': false}})
});
But it does not work. Any idea how to write the query, so that it only return the non-deleted nested comments without creating an independent Comment collection?
EDIT: I didn't mention it's an endpoint where I access only one book object. The resource url is like this: /books/{bookId}/comments
. But also nice to have if it would work when getting all book objects.
Upvotes: 0
Views: 1507
Reputation: 23545
You can use the positional $ operator and filter directly from find. As greatly explaned by @Blakes Seven Here
BookSchema.find({
'comments.is_deleted': false,
}, {
'comments.$': 1,
});
EDIT:
As you said the $ operator
only return one element, here is what the document says :
The positional $ operator limits the contents of an from the query results to contain only the first element matching the query document
There is two solution to your problem:
BookSchema.find({
'comments.is_deleted': false,
}).map(x => Object.assign(x, {
comments: x.comments.filter(y => !y.is_deleted),
}));
The find
get all books that have a non-deleted comment.
The map loop on each book.
We then remove the comments marked as deleted
Upvotes: 1