Mongoose:确保数组永远不会超过一定数量的项



试图找出Mongoose中set操作的确切语法。我有一个看起来像这样的模式:

const userSchema = mongoose.Schema({
instagram: {
images: [{
id: { type: String },
media_type: { type: String },
media_url: { type: String },
timestamp: { type: Date }
}]
}
});

我会定期用用户最新的Instagram照片更新这个阵列,比如:

User.findOneAndUpdate({ _id }, { $addToSet: { "instagram.images": { $each: arr } } });

如何确保阵列更新了最新的图像,但永远不会超过30个图像?功能应该是,如果阵列有20个图像,并且有11个新图像要添加,那么所有11个新的图像都应该添加到阵列中,并且应该删除阵列中当前存在的最后一个项目。

使用$addToSet运算符无法实现这一点。您有两个选项:

  1. 确保您只获取唯一的图像,然后可以使用$push和$slice运算符来实现这一点
User.findOneAndUpdate({ _id }, 
{ $push: { "instagram.images": { $each: arr, $slice: -30 } } });
  1. 如果您不能确保唯一的图像,则必须获取用户并在代码中过滤数组,然后才能继续更新:
let user = User.findOne({_id});
// whatever unique indentifier makes an image "unqiue"
let imagesIds = user.instagram.images.map(v => v.id);
let fileterdImages = arr.filter((elem => !imagesIds.includes(elem.id)));

最后使用选项1中的语法fileterdImages:

User.findOneAndUpdate({ _id }, 
{ $push: { "instagram.images": { $each: fileterdImages, $slice: -30 } } });

请注意,mongoose倾向于为嵌套对象自动生成_id字段,这使得$addToSet一开始就不那么相关。

如果我正确理解您的逻辑,请尝试$size运算符,如下所示:

const T = async () => {
try {
//The result document won't be found, if array_field have more then 30 elements.
let result = User.findOneAndUpdate({$expr: {$lte: [{$size: "$array_field"}, 30]}});
if (!result) {
//No such documents
} else {
//you could add as much elements as you want via for loop for example
result.array_field.addToSet(element)
//also you could check your array_field.length after it, before saving
await result.save()
}
} catch (e) {
console.error(e)
}
}

因此,如果array_field少于30个元素,它就会被找到,因此会被更新。您也可以将$size与比较运算符组合:$gte/$lte

$addToSet向您保证,您使用唯一的值更新了数组。因此,在保存到集合之前,您可以再次检查它(如果您希望的话(。