Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js MongoDB:处理自动递增的模型id';s而不是Mongo';s原生ObjectID_Node.js_Mongodb_Mongoose - Fatal编程技术网

Node.js MongoDB:处理自动递增的模型id';s而不是Mongo';s原生ObjectID

Node.js MongoDB:处理自动递增的模型id';s而不是Mongo';s原生ObjectID,node.js,mongodb,mongoose,Node.js,Mongodb,Mongoose,由于管理层的决定,我们将userId用于users集合,postId用于posts集合,topicId用于topics集合,而不是将每个集合的“_id”用作唯一标识符 这会在开始时引起一些问题-我遇到的问题之一是与upserts有关- 使用Mongoose,我们有一个模式,该模式将userId限制为唯一值-但是当对用户模型进行更新时,upsert设置为true,MongoDB似乎只查看集合的ObjectId,以查看是否存在相同的ObjectId—它不检查是否已经存在具有相同用户ID的模型—因此M

由于管理层的决定,我们将userId用于users集合,postId用于posts集合,topicId用于topics集合,而不是将每个集合的“_id”用作唯一标识符

这会在开始时引起一些问题-我遇到的问题之一是与upserts有关-

使用Mongoose,我们有一个模式,该模式将userId限制为唯一值-但是当对用户模型进行更新时,upsert设置为true,MongoDB似乎只查看集合的ObjectId,以查看是否存在相同的ObjectId—它不检查是否已经存在具有相同用户ID的模型—因此Mongo执行插入而不是更新

让我用一些数据来说明这一点:

假设用户的集合有一个文档:

{
_id:'561b0fad638e99481ab6d84a'
userId:3,
name:'foo'
}
然后我们运行:

User.update({userId:3},{"$set":{name:'bar'},{upsert:true},function(err,resp){

if(err){

   // "errMessage": "insertDocument :: caused by :: 11000 E11000 duplicate key error index: app42153482.users.$userId_1  dup key: { : 3 }",
}

});

有人可能会认为MongoDB会找到userId为3的现有文档并将其删除,所以一定是我做错了什么,因为它给了我重复的密钥错误?

我不知道您使用的是MongoDB和Mongoose的哪个版本,但我无法重现您在MongoDB 3.0和Mongoose 4.1.10中遇到的问题

我为您制作了一个示例,它将创建并保存一个新用户,更新(使用upsert)它,并通过upsert创建另一个用户。尝试运行以下代码:

"use strict";
var mongoose=require("mongoose");
var Schema = require('mongoose').Schema;
var ObjectId = mongoose.Schema.Types.ObjectId;

// Connect to test
mongoose.connect("mongodb://localhost:27017/test");

// Lets create your schema
var userSchema = new Schema({
    _id: ObjectId,
    userId: {type: Number, unique: true },
    name: String
});

var User = mongoose.model("User", userSchema, "Users");


User.remove() // Let's prune our collection to start clean
    .then( function() {
        // Create our sample record
        var myUser = new User({
            _id:'561b0fad638e99481ab6d84a',
            userId:3,
            name:'foo'
        });

        return myUser.save();
    })
    .then( function() {
        // Now its time to update (upsert userId 3)
        return User.update({userId:3},{"$set":{name:'bar'}},{upsert:true});
    })
    .then( function() {
        // Now its time to insert (upsert userId 4)
        return User.update({userId:4},{"$set":{name:'bee'}},{upsert:true});
    })
    .then( function() {
        // Lets show what we have inserted
        return User.find().then(function(data) {console.log(data)});
    })
    .catch( function(err) {
        // Show errors if anything goes wrong
        console.error("ERROR", err);
    })
    .then( function() {
        mongoose.disconnect();
    });

通常,默认值ObjectId对于_id更为理想。在这种情况下,您可以覆盖默认的_id,也可以为id设置自己的字段(如您案例中的userId)

使用单独的计数器集合跟踪使用的最后一个数字序列。\u id字段包含序列名称,seq字段包含序列的最后一个值

将userid的初始值插入到计数器集合中:

db.counters.insert(    {
      _id: "userid",
      seq: 0    } )
创建一个接受序列名称的getNextSequence函数。函数使用findAndModify()方法以原子方式递增seq值并返回此新值:

function getNextSequence(name) {
   var ret = db.counters.findAndModify(
          {
            query: { _id: name },
            update: { $inc: { seq: 1 } },
            new: true
          }
   );

   return ret.seq;
}
在插入()过程中使用此函数

db.users.insert(
   {
     _id: getNextSequence("userid"),
     name: "Sarah C."
   }
)

db.users.insert(
   {
     _id: getNextSequence("userid"),
     name: "Bob D."
   }
)
这样,您可以在同一计数器集合中维护任意多个序列。对于upsert问题,请查看此链接中的乐观循环

第二种方法是使用mongoose中间件,如


希望能有帮助

遵循文档(MongoDB 3.0)upsert:true仅当您的查询条件与_id字段匹配时才会插入不存在的文档

见:

为什么不使用用户的用户名作为唯一id

因为在mongodb环境中使用自动递增字段作为ID是一种不好的做法,特别是如果您想使用分片 =>所有插入都将发生在最新的碎片上 =>mongodb集群必须经常重新平衡/重新分发周围的数据。 (由于您仍然使用生成的_id字段,因此当前系统上不会出现这种情况)

当然,您也可以在用户id字段上创建唯一索引:

这可能会引起您的兴趣。我觉得奇怪的是,在这种情况下,它试图插入一条新记录,而其中一条显然已经存在,并且应该与使用的查询相匹配。是的,我也觉得奇怪,当然我做错了什么,但我不知道是什么,我知道我在第一次搬到mongodb时考虑做同样的事情时遇到了同样的问题,但我认为我从来没有解决过这个问题,我最终找到了我链接的文章,并认为这条路线不适合我们。这种解决方法可行,但我想找出为什么会出现最初的问题。我不明白为什么使用数字增量设置用户ID是一个分片问题。我认为创建一个用户配置文件只需一次,而设置和我们如何设置用户ID对于分片系统来说是完全未知的。你能告诉我这个getNextSequence()函数是你在mongodb(过程)或你的服务器上创建的吗???@Sudhansu你可以在服务器级别创建它作为一个数据库实用程序函数。