在MongoDB
中,我正在寻找一种方法来ATOMICally更新多个文档并在一次通话中返回所有更新的文档。
我们可以在MongoDB
中执行以下所有操作:
findAndModify
或findOneAndUpdate
update(...{multi: true}
或updateMany
find
我还没有想过更新多个文档并在一次通话中全部归还的方法。有办法吗?我使用Mongoose
作为查询包。
答案 0 :(得分:1)
以原子方式更新多个文档:
update(...{multi: true}
或updateMany
不公平地说这是错误的:
但是,您可以模拟一个事务,以"using a two-phase commit approach"的形式原子地更新多个文档,详细描述如下。
您还可以查看$isolated
运算符,"prevents a write operation that affects multiple documents from yielding to other reads or writes once the first document is written"但"does not provide “all-or-nothing” atomicity for write operations"
总结一下,mongodb级别(也不是驱动程序)是不可能的,但您可以在应用程序级别进行模拟,从而返回您需要的内容。
答案 1 :(得分:0)
我测试了updateMany。
测试1:
使用updateMany(pull)更新40K文档,在执行期间,突然关闭db,然后一些节点通过(数据被拔出),一些失败(数据未在树中的某些5级节点中拉出),重启db和再次运行updateMany,全部通过,所有数据现在都正确。
测试2:
在字段上创建唯一索引,插入一些数据,在updateMany方法中,某些文档因唯一键违规而失败。
我的test2结果是:零文档已更新。
function insertData() {
const dataSource = app.models.Entity.getDataSource();
return new Promise((resolve, reject) => {
dataSource.connector.connect((err, db) => {
if (err) {
reject(new Error('.... error'));
return;
}
const entityCollection = db.collection('Entity');
// Create index
entityCollection.createIndex({ age: 1 }, { unique: true })
.then(() => {
// Insert data
const data = [
{
id: uuid.v4(),
age: 1,
type: 'test',
},
{
id: uuid.v4(),
age: 2,
type: 'test',
},
{
id: uuid.v4(),
age: 3,
type: 'test',
},
{
id: uuid.v4(),
age: 4,
type: 'test',
},
{
id: uuid.v4(),
age: 5,
type: 'test',
},
{
id: uuid.v4(),
age: 6,
type: 'test',
},
];
return insertData(data);
})
.then(() => {
resolve();
})
.catch((err2) => {
reject(err2);
});
});
});
}
function updateAge() {
const dataSource = app.models.Entity.getDataSource();
return new Promise((resolve, reject) => {
dataSource.connector.connect((err, db) => {
if (err) {
reject(new Error('...error'));
return;
}
const entityCollection = db.collection('Entity');
entityCollection.updateMany(
{ age: { $gt: 0 } },
{ $mul: { age: 2 } },
).then(() => {
resolve();
})
.catch((err2) => {
logger.error(`ERROR is ${err2}`);
reject(err2);
});
});
});
}
测试结果为:零文档已更新。 " msg":"错误是MongoError:E11000重复键错误集合:content-base.Entity index:age_1 dup key:{:2}"," v&#34 ;:1} 1)更新许多测试
传递0次(114ms) 1失败答案 2 :(得分:0)
MongoDB v3.6引入了会话,可以实现以下目的:https://docs.mongodb.com/manual/reference/method/Session/。我使用猫鼬,这使得使用它们非常简单。这样的事情可能适用于您的情况:
const session = await mongoose.startSession();
return session.withTransaction(async () => {
await SomeModel.update({
foo: "bar"
}, {
$set: {
quux:"baz"
}
});
// NOTE This returns a promise, that is what withTransaction expects
return SomeModel.find({
foo: bar
});
});