Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/34.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 如果不存在,如何创建项;如果存在,如何返回错误_Node.js_Mongodb_Mongoose - Fatal编程技术网

Node.js 如果不存在,如何创建项;如果存在,如何返回错误

Node.js 如果不存在,如何创建项;如果存在,如何返回错误,node.js,mongodb,mongoose,Node.js,Mongodb,Mongoose,我正在写alexa skill,希望检查MongoDB中是否存在用户。我的代码可以工作,但如果用户已经在数据库中,我不知道如何定义这种情况:( 每次执行代码时,我都会得到: “你好,安娜,你是新来的” 我的用户Anna保存在MongoDB中 但我想区分我的用户何时已经在数据库中,并对此作出反应 有谁能解决我的问题吗 var myName = "Anan1"; var userID = this.event.session.user.userId; console.log(

我正在写alexa skill,希望检查MongoDB中是否存在用户。我的代码可以工作,但如果用户已经在数据库中,我不知道如何定义这种情况:(

每次执行代码时,我都会得到: “你好,安娜,你是新来的”

我的用户Anna保存在MongoDB中

但我想区分我的用户何时已经在数据库中,并对此作出反应

有谁能解决我的问题吗

    var myName = "Anan1";
    var userID = this.event.session.user.userId;
    console.log(userID);

    self = this;
    User.findOneAndUpdate(
        {userId:  userID},
        {$set:{name:myName}},
        {upsert: true, new: false, runValidators: true},
        function(err, doc){
            if(err){
                console.log("eeoror");
            }

            console.log(doc);
            if (doc==null){
                self.emit(':ask',
                    "Hello "+ myName +"you are new here")
            }else {
                self.emit(':ask',
                    "Hello "+ myName +"you are not new here")
            }

        });

听起来,你真正想要的是一个成功的人,而不是一个成功的人

可以在[mongoose]中使用模式字段选项设置唯一键:

const s = new Schema({ name: { type: String, unique: true }});
或通过以下方法:

如果试图创建一个文档,但该文档已包含该键的条目,则将抛出一个错误:

注意:违反该约束将在保存时从MongoDB返回E11000错误,而不是Mongoose验证错误


正如前面的评论所述,您有两种基本方法来确定某个东西是否是“创建”的。它们是:

  • 返回响应中的
    rawResult
    ,并检查
    updatedeexisting
    属性,该属性告诉您是否为“upsert”

  • 设置
    new:false
    ,以便在结果中实际返回“no document”,而实际上是“upsert”

作为清单,以证明:

const { Schema } = mongoose = require('mongoose');

const uri = 'mongodb://localhost/thereornot';

mongoose.set('debug', true);
mongoose.Promise = global.Promise;

const userSchema = new Schema({
  username: { type: String, unique: true },   // Just to prove a point really
  password: String
});

const User = mongoose.model('User', userSchema);

const log = data => console.log(JSON.stringify(data, undefined, 2));

(async function() {

  try {

    const conn = await mongoose.connect(uri);

    await Promise.all(Object.entries(conn.models).map(([k,m]) => m.remove()));

    // Shows updatedExisting as false - Therefore "created"

    let bill1 = await User.findOneAndUpdate(
      { username: 'Bill' },
      { $setOnInsert: { password: 'password' } },
      { upsert: true, new: true, rawResult: true }
    );
    log(bill1);

    // Shows updatedExisting as true - Therefore "existing"

    let bill2 = await User.findOneAndUpdate(
      { username: 'Bill' },
      { $setOnInsert: { password: 'password' } },
      { upsert: true, new: true, rawResult: true }
    );
    log(bill2);

    // Test with something like:
    // if ( bill2.lastErrorObject.updatedExisting ) throw new Error("already there");


    // Return will be null on "created"
    let ted1 = await User.findOneAndUpdate(
      { username: 'Ted' },
      { $setOnInsert: { password: 'password' } },
      { upsert: true, new: false }
    );
    log(ted1);

    // Return will be an object where "existing" and found
    let ted2 = await User.findOneAndUpdate(
      { username: 'Ted' },
      { $setOnInsert: { password: 'password' } },
      { upsert: true, new: false }
    );
    log(ted2);

    // Test with something like:
    // if (ted2 !== null) throw new Error("already there");

    // Demonstrating "why" we reserve the "Duplicate" error
    let fred1 = await User.findOneAndUpdate(
      { username: 'Fred', password: 'password' },
      { $setOnInsert: { } },
      { upsert: true, new: false }
    );
    log(fred1);       // null - so okay

    let fred2 = await User.findOneAndUpdate(
      { username: 'Fred', password: 'badpassword' }, // <-- dup key for wrong password
      { $setOnInsert: { } },
      { upsert: true, new: false }
    );

    mongoose.disconnect();

  } catch(e) {
    console.error(e)
  } finally {
    process.exit()
  }


})()
因此,第一个案例实际上考虑了以下代码:

User.findOneAndUpdate(
  { username: 'Bill' },
  { $setOnInsert: { password: 'password' } },
  { upsert: true, new: true, rawResult: true }
)
这里的大多数选项都是标准的,因为“所有”
“upsert”
操作将导致用于“匹配”的字段内容(即
用户名
)是在新文档中创建的“始终”,因此您不需要修改该字段。为了不实际“修改”您可以在后续请求上使用的其他字段,这些字段仅在未找到匹配项的
“upsert”
操作期间添加这些属性

这里,标准的
new:true
用于从操作返回“修改过的”文档,但区别在于
rawResult
,如返回的响应所示:

{
  "lastErrorObject": {
    "n": 1,
    "updatedExisting": false,
    "upserted": "5adfc8696878cfc4992e7634"
  },
  "value": {
    "_id": "5adfc8696878cfc4992e7634",
    "username": "Bill",
    "__v": 0,
    "password": "password"
  },
  "ok": 1,
  "operationTime": "6548172736517111811",
  "$clusterTime": {
    "clusterTime": "6548172736517111811",
    "signature": {
      "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
      "keyId": 0
    }
  }
}
您从驱动程序获得的不是“mongoose文档”,而是实际的“原始”响应。实际文档内容位于
“value”
属性下,但我们感兴趣的是
“lastErrorObject”

这里我们看到属性
updatedeExisting:false
。这表示实际上没有找到“匹配项”,因此“创建”了一个新文档。因此,您可以使用该属性来确定实际发生的创建

再次发出相同的查询选项时,结果将不同:

{
  "lastErrorObject": {
    "n": 1,
    "updatedExisting": true             // <--- Now I'm true
  },
  "value": {
    "_id": "5adfc8696878cfc4992e7634",
    "username": "Bill",
    "__v": 0,
    "password": "password"
  },
  "ok": 1,
  "operationTime": "6548172736517111811",
  "$clusterTime": {
    "clusterTime": "6548172736517111811",
    "signature": {
      "hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
      "keyId": 0
    }
  }
}
大多数相同的情况都适用,只是现在操作是返回文档的原始状态,而不是在“操作”之后返回文档的“修改”状态。因此,当没有与“查询”语句实际匹配的文档时,返回的结果是
null

Mongoose: users.findAndModify({ username: 'Ted' }, [], { '$setOnInsert': { password: 'password', __v: 0 } }, { upsert: true, new: false, remove: false, fields: {} })
null           // <-- Got null in response :(
因此,任何“not
null
”的响应都表示文档已经存在,并且您可以根据响应中实际接收到的内容来分支逻辑

因此,这是两种基本的方法来回答你的问题,它们肯定是“起作用的”!正如在这里用同样的陈述所演示和再现的一样


附录-为错误密码保留重复密钥 完整列表中还暗示了一种更有效的方法,这基本上就是简单地
.insert()
(或
.create()
来自mongoose模型)新数据,并在“unique”处抛出“replicate key”错误这是一种有效的方法,但在“用户验证”中有一个特殊的用例,这是一种方便的逻辑处理,即“验证密码”

因此,通过
用户名
密码
组合来检索用户信息是一种非常常见的模式。在“upsert”的情况下,这种组合被证明是“唯一的”,因此,如果没有找到匹配项,就会尝试“插入”。这正是使匹配密码成为一种有用的实现的原因

考虑以下几点:

    // Demonstrating "why" we reserve the "Duplicate" error
    let fred1 = await User.findOneAndUpdate(
      { username: 'Fred', password: 'password' },
      { $setOnInsert: { } },
      { upsert: true, new: false }
    );
    log(fred1);       // null - so okay

    let fred2 = await User.findOneAndUpdate(
      { username: 'Fred', password: 'badpassword' }, // <-- dup key for wrong password
      { $setOnInsert: { } },
      { upsert: true, new: false }
    );
因此,您应该意识到,您现在获得了三个“免费”评估的条件。即:

  • “upsert”由
    更新的existing:false
    null
    结果记录,具体取决于方法
  • 您可以通过
    updatedeexisting:true
    或文档返回的“not
    null
    ”来知道文档(通过组合)“存在”
  • 如果提供的
    密码
    用户名
    的现有密码不匹配,则您将获得“重复密钥错误”,您可以捕获该错误并相应地作出响应,并建议用户响应“密码不正确”
所有这些都来自一个请求


这是使用“upserts”而不是简单地向集合抛出insert的主要原因,因为您可以获得不同的逻辑分支,而无需向数据库发出额外的请求来确定“哪个”这些条件中应该有实际的响应。

你可以做
new:false
,只需检查返回的文档是否为
null
。也就是说,not
null
表示它以前存在,
null
表示它已创建。在这种情况下,你基本上应该拥有所有文档的详细信息,所以你可能不知道'不需要匹配的返回值。或者,您可以请求
rawResponse
,它应该指示
是否发生了upsert
。此外,您可能真的希望
$setOnInsert
在这里。它不起作用:(我一直在打招呼您不是新来的。我更新了我的代码,请您看看:)这实际上并不重要,因为操作已声明为使用
upsertUser.findOneAndUpdate(
  { username: 'Ted' },
  { $setOnInsert: { password: 'password' } },
  { upsert: true, new: false }
)
Mongoose: users.findAndModify({ username: 'Ted' }, [], { '$setOnInsert': { password: 'password', __v: 0 } }, { upsert: true, new: false, remove: false, fields: {} })
null           // <-- Got null in response :(
{
  "_id": "5adfc8696878cfc4992e7639",
  "username": "Ted",
  "__v": 0,
  "password": "password"
}
    // Demonstrating "why" we reserve the "Duplicate" error
    let fred1 = await User.findOneAndUpdate(
      { username: 'Fred', password: 'password' },
      { $setOnInsert: { } },
      { upsert: true, new: false }
    );
    log(fred1);       // null - so okay

    let fred2 = await User.findOneAndUpdate(
      { username: 'Fred', password: 'badpassword' }, // <-- dup key for wrong password
      { $setOnInsert: { } },
      { upsert: true, new: false }
    );
{ MongoError: E11000 duplicate key error collection: thereornot.users index: username_1 dup key: { : "Fred" }