【问题标题】:Insert an array of documents into a model将文档数组插入模型
【发布时间】:2014-09-04 04:44:25
【问题描述】:

以下是相关代码:

var Results = mongoose.model('Results', resultsSchema);
var results_array = [];

_.each(matches, function(match) {
    var results = new Results({
        id: match.match_id,
        ... // more attributes
    });
    results_array.push(results);
});
callback(results_array);
});
   }
], function(results_array) {
   results_array.insert(function(err) {
       // error handling

当然,我会得到一个No method found 对应的results_array。但是我不确定还有什么可以调用该方法。

在其他函数中,我在这里传递了与 results 变量等效的变量,它是一个猫鼬对象,并且具有可用的 insert 方法。

如何在此处插入文档数组?

** 编辑 **

function(results_array) {
            async.eachLimit(results_array, 20, function(result, callback) {
                result.save(function(err) {
                    callback(err);
                });
            }, function(err) {
                if (err) {
                    if (err.code == 11000) {
                        return res.status(409);
                    }
                    return next(err);
                }
                res.status(200).end();
                });
            });

那么发生了什么:

当我清除集合时,这工作正常。 但是,当我重新发送此请求时,我从未收到任何回复。

发生这种情况是因为我的架构不允许来自 JSON 响应的重复项。因此,当我重新发送请求时,它会获得与第一个请求相同的数据,因此会以错误响应。这就是我认为状态码409 处理的内容。

在我的实现中是否有错字?

编辑 2

错误代码出来了:

{ [MongoError: insertDocument :: caused by :: 11000 E11000 duplicate key error index:       
test.results.$_id_  dup key: { : 1931559 }]
    name: 'MongoError',
    code: 11000,
    err: 'insertDocument :: caused by :: 11000 E11000 duplicate key error index:    
test.results.$_id_  dup key: { : 1931559 }' }

所以这正如预期的那样。 Mongo 响应 11000 错误,抱怨这是一个重复的键。

编辑 3

if (err.code == 11000) {
    return res.status(409).end();
}

这似乎解决了问题。这是一个创可贴吗?

【问题讨论】:

  • 你到底想做什么?是否有另一个模型具有包含结果数组的文档?还是您想一次插入一大堆“结果”文档?
  • 您不能将return 与回调混用。 console.log(err) 看看会发生什么。与 err.code 和其他可能与您预期不匹配的内容相同。但肯定会在此处重复键,这适用于空集合。
  • 在细节中进行了编辑,但错误代码与我预期的一样。我只是不确定在这种情况下return 的替代方案是什么。我想说的是,当错误代码为11000 时,使用409 代码或适当的代码进行响应并结束请求/响应周期。目前没有发生这种情况,我不确定具体原因。
  • 这里的提示是您要问的问题不止一个。回答了一部分,即如何插入您的文档数组。现在你在问如何使用 express 这真的是另一个问题。但基本上你应该只想要res.status(409).end() 而你不要在这些东西前面加上return
  • 啊我的错。我是新来的,只是想学习一些技巧。不过,这不是借口,我会尝试拿起我的游戏。是的,这解决了我的问题,谢谢尼尔。

标签: javascript node.js mongodb mongodb-query


【解决方案1】:

您似乎试图在此处一次插入各种文档。所以你实际上有几个选择。

首先,mongoose 中没有 .insert() 方法,因为它被其他包装器取代,例如 .save().create()。这里最基本的过程是在您刚刚创建的每个文档上调用“保存”。还在这里使用async 库来实现一些流控制,所以一切都不会排队:

async.eachLimit(results_array,20,function(result,callback) {
    result.save(function(err) {
        callback(err)
    });
},function(err) {
   // process when complete or on error
});

这里的另一件事是.create() 可以只接受一个对象列表作为它的参数,并在创建文档时简单地插入每个对象:

Results.create(results_array,function(err) {

});

这实际上是使用“原始”对象,因为它们基本上都首先被转换为猫鼬文档。您可以要求将文档作为回调签名中的附加参数返回,但构造这可能是矫枉过正。

无论采用哪种方式,“异步”表单都会并行处理,“创建”表单将按顺序处理,但它们都有效地为每个创建的文档向数据库发出一个“插入”。

对于真正的批量功能,您目前需要解决底层驱动程序方法,最好的地方是Bulk Operations API

mongoose.connection.on("open",function(err,conn) {

    var bulk = Results.collection.initializeUnorderedBulkOp();
    var count = 0;

    async.eachSeries(results_array,function(result,callback) {
        bulk.insert(result);
        count++;

        if ( count % 1000 == 0 ) {
            bulk.execute(function(err,response) {
               // maybe check response
               bulk = Results.collection.initializeUnorderedBulkOp();
               callback(err);
            });
        } else {
            callback();
        }

    },function(err) {
        // called when done
        // Check if there are still writes queued
        if ( count % 1000 != 0 )
            bulk.execute(function(err,response) {
               // maybe check response
            });
    });

});

这里的数组再次是原始对象,而不是那些被转换为猫鼬文档的对象。这里没有实现验证或其他猫鼬模式逻辑,因为这只是一个基本的驱动程序方法,不知道这些事情。

虽然数组是按顺序处理的,但上面显示了写入操作实际上只会每处理 1000 个条目或到达末尾时才会发送到服务器一次。所以这确实会立即将所有内容发送到服务器。

无序操作意味着err 通常不会被设置,而是“响应”文档将包含任何可能发生的错误。如果您希望它在第一个错误时失败,那么它将改为 .initializeOrderedBulkOp()

这里需要注意的是,您必须在以这种方式访问​​这些方法之前确保连接已打开。 Mongoose 使用它自己的方法来处理连接,因此在与数据库建立实际连接之前,在代码中到达诸如 .save() 之类的方法时,它在某种意义上是“排队”等待此事件。

因此,要么确保首先完成其他一些“猫鼬”操作,要么确保您的应用程序逻辑在肯定会建立连接的情况下正常工作。在此示例中通过放置在“连接打开”事件中进行模拟。

这取决于你真正想做什么。每种情况都有其用途,当然最后一种是最快的方法,因为与服务器来回的“写入”和“返回结果”对话有限。

【讨论】:

  • 嗨,尼尔,感谢您的回复。我已经进行了编辑,以显示我对您的第一个建议的尝试以及我遇到的问题。干杯
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-07-11
  • 2021-01-10
  • 2021-09-29
  • 2017-09-14
  • 2017-02-25
  • 1970-01-01
  • 2016-04-17
相关资源
最近更新 更多