Mongoose FindOne在创建后不能直接工作

时间:2015-09-07 22:31:27

标签: javascript mongodb mongoose mongoose-plugins

我正在设置种子数据,目标是只创建一条记录(如果它还不存在)。

我使用https://www.npmjs.com/package/mongoose-find-one-or-create插件只创建记录,如果它们不存在且无法正常工作。

我还调试了他们的代码并编写了我自己的测试。

  • 创建记录 - 名称='Abc'
  • 查找记录名称='Abc'
  • 如果找到
  • print found
  • 如果没有找到
  • 创建记录 - 名称='Xyz'

我原本希望看到“发现”这个消息,但我得到一条名为'Xyz'的新记录

我感觉它可能是某种异步问题,但我是mongo的新手,所以不完全确定。

以下是我的所有测试代码,以及plugin中的代码。

帐户表的方案定义

'use strict';

var mongoose = require('mongoose');
var findOneOrCreate = require('mongoose-find-one-or-create');

var Schema = mongoose.Schema;

var AccountSchema = new Schema({
  name: String,
  type: String,
  notes: String,
  locationIds: String,
});


AccountSchema.plugin(findOneOrCreate);

module.exports = mongoose.model('Account', AccountSchema);

用于创建新行的种子文件

'use strict';

var Account = require('../../api/account/account.model');

Account.create({ name: 'Abc' }, function (err, small) {
});

Account.findOne({ name: 'Abc' }, function (err, row) {

  console.log("Inside Find One");
  if (row) {
    console.log("Found: Yes");
    console.log(row);
  } else {
    console.log("NOT FOUND");
    Account.create({ name: 'Xyz' }, function (err, small) {
    });
  }
});

FindOneOrCreatePlugin代码

'use strict';

/**
 * Mongoose Plugin: findOneOrCreate
 * Copyright(c) 2014 Mohammad Khan <mohammad.khan@gmx.us>
 * MIT Licensed
**/

function findOneOrCreatePlugin(schema) {
  //console.log('findOneOrCreatePlugin: SETUP');
    schema.statics.findOneOrCreate = function findOneOrCreate(condition, doc, callback) {
        var self = this;
        //console.log('CONDITION');
        //console.log('----------------------------------------------------------------------------------------------------');
        //console.log(condition);
        //console.log('----------------------------------------------------------------------------------------------------');

        self.findOne(condition, function(err, result ) {
          //console.log('ERROR');
          //console.log('----------------------------------------------------------------------------------------------------');
          //console.log(err);
          //console.log('----------------------------------------------------------------------------------------------------');
          //console.log('RESULT');
          //console.log('----------------------------------------------------------------------------------------------------');
          //console.log(result);
          //console.log('----------------------------------------------------------------------------------------------------');

          if (result) {
            //console.log('----------------------------------------------------------------------------------------------------');
            //console.log('YEEEEEEEEEEEEEEY an UPDATE');
            //console.log('----------------------------------------------------------------------------------------------------');

                callback(err, result);
          } else {
            //console.log('CREATE');
            //console.log('----------------------------------------------------------------------------------------------------');
            //console.log(doc);
            //console.log('----------------------------------------------------------------------------------------------------');

                self.create(doc, function(err, result) {
                    callback(err, result);
                });
            }
        });
    };
}

module.exports = findOneOrCreatePlugin;

在Mongo Shell中查询

Mongo Shell Output

Web服务器中的控制台输出

Console Output in Web Server

**这是我试图处理的用例**

注意:这是最终用户使用

生成的一组文件的一部分

我试图解决的USE案例是,如果用户意外地将同一帐户放入两次。

当用户意外地放入重复项时,此代码本质上意味着自我修复,它只是用于填充新应用程序的种子系统。

我打算在产品表上使用它,产品表有1000个产品。

根据@RobertMoskal的说法,我需要将调用放在回调函数中,但是我会有大量的嵌套回调函数,每个产品都有1个。

// Create account called 'Chicane'
Account.findOneOrCreate(
    { name: 'Chicane'},
    {
        name: 'Chicane',
        type: 'Orderer',
    },
    function (err, account) {
        console.log('Account.findOneOrCreate');
        console.log(account);
    }
);

// Create account called 'Campos'
Account.findOneOrCreate(
    { name: 'Campos'},
    {
        name: 'Campos',
        type: 'Supplier',
    },
    function (err, account) {
        console.log('Account.findOneOrCreate');
        console.log(account);
    }
);

// Create account called 'Chicane', this has already been created so it should NOT be created again, but it is
Account.findOneOrCreate(
    { name: 'Chicane'},
    {
        name: 'Chicane',
        type: 'Orderer',
    },
    function (err, account) {
        console.log('Account.findOneOrCreate');
        console.log(account);
    }
);

1 个答案:

答案 0 :(得分:1)

经典节点错误。您必须在create函数的回调中调用findOne函数,否则将在create函数完成之前调用它。所以像这样:

Account.create({ name: 'Abc' }, function (err, small) {
    if(err)...;
    Account.findOne({ name: 'Abc' }, function (err, row) {...
    });
});

使用findOneOrCreate插件天真地加载数千个项目会导致回调地狱。但是您可以看到过程的重复性,您可以使用async库之类的东西来确保代码按顺序运行:

async.series([
    function(cb){ Account.findOneOrCreate({...})},
    function(cb){ { Account.findOneOrCreate({...}, cb)}
]);