mongoose 如何一次性更新大量文档?急。
发布于 7 年前 作者 JZLeung 4563 次浏览 来自 问答

在做 node 爬虫。

目前用的是 BulkWrite :

const Book = mongoose.model('Book', bookSchema);
exports.saveAll = (from_en, books) => {
    const bulkWrite = books.map(book => ({
        replaceOne: {
            filter: {
                from_en,
                originId: book.originId
            },
            replacement: book,
            upsert: true
        }
    }))
    return Book.bulkWrite(bulkWrite).catch(error => console.error(error))
}

然后发现,这么处理 11200 条数据耗时 600s:

catId: 82 from 5040 to 5600. crawl cost: 10.1min, dataTotal: 11200, upsertTotal: 11000, matchTotal: 200
mongodb is disonnected
mongodb: 603757.883ms
✨  Done in 604.47s.

这个该如何优化?

下面是部分爬虫逻辑的代码: while 内部的代码

机子性能:I7 6700HQ / 16G RAM

2018年04月28日17:36:55 更新

机子性能:阿里云 双核4G 云主机

现在用 eggjs 的定时任务代替 crontab 的 npm run start,同时,更新的逻辑改为先查询已存在,存在则 replace 不存在则 insert。

但是现在发现, bulkWrite 的时间还是太长了。很容易出现后续的爬虫在更新时发生 connection fail 的错误。

{ MongoError: connection 12 to 127.0.0.1:27017 timed out
    at Function.MongoError.create (/home/website/bookapp-web-test/node_modules/mongodb-core/lib/error.js:29:11)
    at Socket.<anonymous> (/home/website/bookapp-web-test/node_modules/mongodb-core/lib/connection/connection.js:200:20)
    at Object.onceWrapper (events.js:313:30)
    at emitNone (events.js:106:13)
    at Socket.emit (events.js:208:7)
    at Socket._onTimeout (net.js:420:8)
    at ontimeout (timers.js:482:11)
    at tryOnTimeout (timers.js:317:5)
    at Timer.listOnTimeout (timers.js:277:5)
  name: 'MongoError',
  message: 'connection 12 to 127.0.0.1:27017 timed out' }

而且更新的时间也还是达到了 360000ms 之久。

saving catId: 83, result: total -> 11200 matched ->undefined, upsert ->undefined;cost: 366340ms

求助啊,真的急。

7 回复

replaceOne.filter里面的条件有索引吗?

@peasonlee 有。 from_en 是一个字符串。算吗? image.png

redis先存着,后续再写入

来自酷炫的 CNodeMD

什么网页一个页面会有 11200 条数据。。。。。为啥不抓一个存一个。

这种情况不建议你用mongoose,直接用mongodb的3.0驱动,带有队列操作,而且还可以保证每条操作都成功

@MiYogurt 直接抓的 API 接口。

@xivistudios 就是用原生的 mongodb 驱动?

回到顶部