MongoDB中如何实现用户文档books数组的存在则更新、不存在则插入操作?
在MongoDB中实现数组元素的「存在则更新,不存在则插入」操作
嘿,针对你这个用户文档里books数组的更新需求,我刚好有实操经验,MongoDB里可以通过两种常用方式来实现“存在就更新,不存在就插入”的逻辑,下面给你详细拆解:
方式一:分两步判断(兼容低版本MongoDB)
首先得明确:判断图书是否存在的核心标识应该是bookId,毕竟书名、作者这些信息可能变动,用唯一的bookId做判断才靠谱。
假设我们要操作的用户ID是3435,要处理的图书数据是这样的:
const targetUserId = 3435; const bookToHandle = { bookId: 123, name: "更新后的书名", authors: [{ country: "UK", name: "更新后的作者名" }] };
第一步:尝试更新已存在的图书
先执行更新操作,匹配目标用户和对应的图书:
const updateResult = db.users.updateOne( // 匹配条件:找到指定用户,且其books数组里有bookId匹配的项 { id: targetUserId, "books.bookId": bookToHandle.bookId }, // 更新匹配到的那本图书的所有字段 { $set: { "books.$": bookToHandle } }, // 这里不需要创建新用户,所以upsert设为false { upsert: false } );
第二步:如果没找到,就插入新图书
看一下返回的updateResult.modifiedCount,如果是0,说明该用户的books数组里没有这本图书,那就执行追加:
if (updateResult.modifiedCount === 0) { db.users.updateOne( { id: targetUserId }, { $push: { books: bookToHandle } } ); }
这种方式逻辑简单,兼容MongoDB 4.2以下的版本,唯一的小缺点是需要两次数据库调用。
方式二:单语句完成(MongoDB 4.2+推荐)
如果你的MongoDB版本在4.2及以上,推荐用聚合管道来写,把判断和更新逻辑合并成一个语句,效率更高:
db.users.updateOne( { id: targetUserId }, [ { $set: { books: { $cond: [ // 先判断:books数组里有没有bookId匹配的项 { $in: [bookToHandle.bookId, "$books.bookId"] }, // 如果有:遍历数组,替换匹配的项,其他项保持不变 { $map: { input: "$books", as: "item", in: { $cond: [ { $eq: ["$$item.bookId", bookToHandle.bookId] }, bookToHandle, "$$item" ] } } }, // 如果没有:把新图书追加到数组末尾 { $concatArrays: ["$books", [bookToHandle]] } ] } } } ] );
这种写法一次数据库调用就搞定所有逻辑,代码更紧凑高效。
额外提示
- 如果你需要批量处理多个用户或者多本图书,可以把上面的逻辑封装成循环,或者用
updateMany配合arrayFilters来实现批量操作。 - 一定要确保
bookId是唯一的,这样判断才不会出错,避免重复插入或者误更新。
内容的提问来源于stack exchange,提问作者yuji itadori
相关产品推荐
相关产品推荐

