乐闻世界logo
搜索文章和话题

Mongoose 如何更新一条数据/文档?

7 个月前提问
5 个月前修改
浏览次数60

6个答案

1
2
3
4
5
6

在Mongoose中,更新文档(通常在 MongoDB 中称为记录)可以通过几种不同的方法来实现。如果你提到的 "upstart" 文档是指需要更新的文档,那么我将展示几种在 Mongoose 中更新文档的常用方法,并提供示例。

使用 save() 方法更新文档

如果你已经查询到了一个 Mongoose 文档实例,你可以直接修改它的属性,然后调用 .save() 方法来更新它。

javascript
const mongoose = require('mongoose'); const { Schema } = mongoose; const UserSchema = new Schema({ name: String, age: Number }); const User = mongoose.model('User', UserSchema); async function updateUser(userId) { try { // 查询文档 const user = await User.findById(userId); if (user) { // 修改文档的属性 user.name = '新的名字'; user.age = 30; // 保存文档 await user.save(); console.log('Document updated successfully'); } else { console.log('Document not found'); } } catch (error) { console.error('Error updating document:', error); } }

使用 updateOne()updateMany() 方法

如果你不需要先检索整个文档,你可以直接使用 updateOne()updateMany() 方法来更新一个或多个文档。

javascript
async function updateUserName(userId, newName) { try { // 更新单个文档 const result = await User.updateOne({ _id: userId }, { $set: { name: newName } }); if (result.matchedCount === 1) { console.log('Document updated successfully'); } else { console.log('No documents matched the query. Document not updated'); } } catch (error) { console.error('Error updating document:', error); } }

使用 findOneAndUpdate() 方法

如果你想在更新文档的同时检索更新后的文档,你可以使用 findOneAndUpdate() 方法。

javascript
async function findAndUpdateUser(userId, newName) { try { const options = { new: true }; // 返回更新后的文档 const updatedUser = await User.findOneAndUpdate({ _id: userId }, { $set: { name: newName } }, options); if (updatedUser) { console.log('Document updated and retrieved successfully:', updatedUser); } else { console.log('Document not found'); } } catch (error) { console.error('Error finding and updating document:', error); } }

在这些示例中,我们使用了 MongoDB 的更新操作符 $set 来指定我们希望更新的字段。同时还可以使用其他更新操作符来执行更复杂的更新操作。根据你的需求,你可以选择最适合你的更新策略。

注意:确保在执行更新操作时遵循最佳实践,比如验证输入、处理错误等。

2024年6月29日 12:07 回复

Mongoose now supports this natively with findOneAndUpdate (calls MongoDB findAndModify).

The upsert = true option creates the object if it doesn't exist. defaults to false.

shell
var query = {'username': req.user.username}; req.newData.username = req.user.username; MyModel.findOneAndUpdate(query, req.newData, {upsert: true}, function(err, doc) { if (err) return res.send(500, {error: err}); return res.send('Succesfully saved.'); });

In older versions Mongoose does not support these hooks with this method:

  • defaults
  • setters
  • validators
  • middleware
2024年6月29日 12:07 回复

I just burned a solid 3 hours trying to solve the same problem. Specifically, I wanted to "replace" the entire document if it exists, or insert it otherwise. Here's the solution:

shell
var contact = new Contact({ phone: request.phone, status: request.status }); // Convert the Model instance to a simple object using Model's 'toObject' function // to prevent weirdness like infinite looping... var upsertData = contact.toObject(); // Delete the _id property, otherwise Mongo will return a "Mod on _id not allowed" error delete upsertData._id; // Do the upsert, which works like this: If no Contact document exists with // _id = contact.id, then create a new doc using upsertData. // Otherwise, update the existing doc with upsertData Contact.update({_id: contact.id}, upsertData, {upsert: true}, function(err{...});

I created an issue on the Mongoose project page requesting that info about this be added to the docs.

2024年6月29日 12:07 回复

You were close with

shell
Contact.update({phone:request.phone}, contact, {upsert: true}, function(err){...})

but your second parameter should be an object with a modification operator for example

shell
Contact.update({phone:request.phone}, {$set: { phone: request.phone }}, {upsert: true}, function(err){...})
2024年6月29日 12:07 回复

Well, I waited long enough and no answer. Finally gave up the whole update/upsert approach and went with:

shell
ContactSchema.findOne({phone: request.phone}, function(err, contact) { if(!err) { if(!contact) { contact = new ContactSchema(); contact.phone = request.phone; } contact.status = request.status; contact.save(function(err) { if(!err) { console.log("contact " + contact.phone + " created at " + contact.createdAt + " updated at " + contact.updatedAt); } else { console.log("Error: could not save contact " + contact.phone); } }); } });

Does it work? Yep. Am I happy with this? Probably not. 2 DB calls instead of one.
Hopefully a future Mongoose implementation would come up with a Model.upsert function.

2024年6月29日 12:07 回复

I'm the maintainer of Mongoose. The more modern way to upsert a doc is to use the Model.updateOne() function.

shell
await Contact.updateOne({ phone: request.phone }, { status: request.status }, { upsert: true });

If you need the upserted doc, you can use Model.findOneAndUpdate()

shell
const doc = await Contact.findOneAndUpdate({ phone: request.phone }, { status: request.status }, { upsert: true, useFindAndModify: false });

The key takeaway is that you need to put the unique properties in the filter parameter to updateOne() or findOneAndUpdate(), and the other properties in the update parameter.

Here's a tutorial on upserting documents with Mongoose.

2024年6月29日 12:07 回复

你的答案