你知道mongoose中的 __v么

Posted twinkle||cll

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了你知道mongoose中的 __v么相关的知识,希望对你有一定的参考价值。

mongoose 在添加数据的时候,会默认给你加上一个属性__v,这个属性的全称是__version,顾名思义是版本的意思,作用是给每一个文档加上版本控制,防止并发来修改数据库的数据。

mongoose中的并发管理

在mongoose中,我们可以会有以下操作:

当多个异步函数同时操作数据库时,就可能发生这样的情况,具体的场景往往发生在并发请求中

面对这种情况,mongoose作出以下假设:

  • 当修改一个文档时,如果某些字段已经不再和数据库对应,说明这个字段的数据是脏数据(dirty data),对于脏数据,不应该对数据库产生影响
  • 当修改一个文档时,如果字段和数据库是对应的,则是正常数据,正常数据可以正常的更改数据库

修改普通字段

执行以下代码:

async function  findById()
 const stu1 = await StuSchema.findById('6187c8599cf04703abb24c20');
 stu1.stuNo = '20210103';
 stu1.name = 'twinkle';
 await stu1.save();
 const stu2 = await StuSchema.findById('6187c8599cf04703abb24c20');
 stu2.age = 20;
 await stu2.save(); 


findById();
复制代码

因此,mongoose对于上述场景的处理如下:

可以看出,对于user2的修改,nameloginId是脏数据,因此不会更新到数据库中,而age是正常数据,对它的更改会应用到数据库

修改数组

然而,mongoose无法准确的判定对数组是否是脏数据,因此,如果遇到数组的修改,mongoose会做出如下处理:

  • 当新增文档时,会自动添加字段__v,用于记录更新版本号,一开始为0
  • 通过模型实例对数组进行修改后,保存时会在内部调用实例的increment函数,将版本号+1
  • 当其他模型实例也更改了数组,保存时会对比版本号,如果不一致,则会引发VersionError

执行以下代码:

async function  findById()
 const stu1 = await StuSchema.findById('6187c8599cf04703abb24c20');
 const stu2 = await StuSchema.findById('6187c8599cf04703abb24c20');
 stu1.loves = ['code1'];
 await stu1.save();
 stu2.loves = ['game1'];
 await stu2.save();


findById();
复制代码

数据库结果

原理图如下:

出现错误是好事,可以提醒开发者:这一次保存的某些数据是脏数据,应该引起重视。开发者可以灵活的根据具体情况作出处理,比如提示用户保存失败,或者重新获取数据然后保存

由于mongoose仅针对数组进行版本控制,如果要针对所有字段都进行版本控制,需要使用mongoose的插件:mongoose-update-if-current

插件地址:github.com/eoin-obrien…

使用插件后,所有的字段都将受到版本控制,一旦版本不一致,将引发VersionError

以上是关于你知道mongoose中的 __v么的主要内容,如果未能解决你的问题,请参考以下文章

Mongoose 中的“__v”字段是啥

Mongoose 中的“__v”字段是啥

Mongoose 将 _id 更改为 id

Mongoose 错误:无法同时更新 __v 和 __v

Mongoose 错误:无法同时更新 __v 和 __v

如果通过,如何强制 Mongoose 忽略 __v?