I pull a value from an array and immediately add it back to bring it to the front of the array.
await User.findByIdAndUpdate(authenticatedUserId,
{ $pull: { lastVisitedResources: resourceId } },
).exec();
await User.findByIdAndUpdate(authenticatedUserId,
{ $push: { lastVisitedResources: { $each: [resourceId], $position: 0, $slice: -50 } } },
).exec();
Is there a way to execute this more efficiently via a bulk operation?
I tried Mongoose’ bulkWrite as well as MongoDB’s lower-level db.collection.bulkWrite but TypeScript doesn’t accept the $pull
and $push
operators for either of them:
await User.bulkWrite([
{
updateOne: {
filter: { _id: authenticatedUserId },
update: {
$pull: { lastVisitedResources: resourceId }
}
}
},
{
updateOne: {
filter: { _id: authenticatedUserId },
update: {
$push: { lastVisitedResources: { $each: [resourceId], $position: 0, $slice: 50 } }
}
}
}
])
prints the following error:
Type '{ lastVisitedResources: string; }' is not assignable to type 'PullOperator<Document>'.
Type '{ lastVisitedResources: string; }' is not assignable to type '{ readonly [x: string]: Partial<any> | { [x: string]: FilterOperators<any> | undefined; } | FilterOperators<any> | undefined; }'.
Property 'lastVisitedResources' is incompatible with index signature.
Type 'string' is not assignable to type 'Partial<any> | { [x: string]: FilterOperators<any> | undefined; } | FilterOperators<any> | undefined'.ts(2322)
I also tried initializeOrderedBulkOp
but it has no effect:
const bulk = User.collection.initializeOrderedBulkOp();
bulk.find({ _id: authenticatedUserId })
.updateOne({ $pull: { lastVisitedResources: resourceId } });
bulk.find({ _id: authenticatedUserId })
.updateOne({ $push: { lastVisitedResources: { $each: [resourceId], $position: 0, $slice: -50 } } });
await bulk.execute();
2
Answers
Turns out, this is actually a false positive by TypeScript. Following @Tom Slabbaert's suggestion, I added
ts-ignore
to the$push
and$pull
operators and it works properly:Note: If you use the native
db.collection.bulkWrite
instead of Mongoose'sModel.bulkWrite
, you have to cast theid
s fromstring
s tomongoose.Type.ObjectId
s.You can do using the aggregation pipeline updates syntax, like so:
Mongo Playground