Javascript 猫鼬:findOneAndUpdate~500k文档

Javascript 猫鼬:findOneAndUpdate~500k文档,javascript,node.js,mongodb,mongoose,Javascript,Node.js,Mongodb,Mongoose,由于我想更新整个文档集合,有些可能存在,有些没有500k条目的文档,所以我循环使用来自CSV的纯JS对象,并通过findOneAndUpdate方法更新所有文档 下面是一个简化的JS代码: const mongoose = require("mongoose"); const { mongoUrl } = require("../config.js"); const MyModel = require("../models/MyModel"); async function run() {

由于我想更新整个文档集合,有些可能存在,有些没有500k条目的文档,所以我循环使用来自CSV的纯JS对象,并通过findOneAndUpdate方法更新所有文档

下面是一个简化的JS代码:

const mongoose = require("mongoose");
const { mongoUrl } = require("../config.js");
const MyModel = require("../models/MyModel");

async function run() {
  mongoose.set("useCreateIndex", true);
  await mongoose.connect(mongoUrl, { useNewUrlParser: true });

  const r = [/* */]; // <-- Something with 500k objects

  const total = r.length;
  for (let i in r) {
    const e = r[i];
    e.REF = e.REF.trim();
    await MyModel.findOneAndUpdate({ REF: e.REF }, e, { upsert: true, new: true });
    if (i % 500 === 0) {
      console.log((i / total) * 100 + "%");
    }
  }
}

run();

第一次插入的速度超过每秒500次,但当它达到25%时,对于500个条目,它开始非常慢10秒或更长时间。我想冷冻会慢一点吗?接近80%

有没有更好的方法来做这样的事情?我怎样才能加快速度


我的意思是,它只有50万个实体,有很多属性,但我认为这并不重要。

我可以想到两种更有效的方法

确保在REF上有索引

创建批处理更新,而不是逐个等待


有两种方法可以让你更有效地做到这一点,我可以想到

确保在REF上有索引

创建批处理更新,而不是逐个等待


将评论作为答案发布:


你有吗?否则,数据库将必须扫描整个集合,以确定是否存在具有相同参考的模型。

将注释发布为答案:


你有吗?否则,数据库将不得不扫描整个集合,以确定是否存在具有相同引用的模型。

我曾经为数据库模型迁移执行过此类操作,我发现。bulkWrite在这里确实起到了作用。我要做的是:

const mongoose = require("mongoose");
const { mongoUrl } = require("../config.js");
const MyModel = require("../models/MyModel");

async function run() {
  mongoose.set("useCreateIndex", true);
  await mongoose.connect(mongoUrl, { useNewUrlParser: true });

  const r = [/* */]; // <-- Something with 500k objects

  const total = r.length;
  // Set empty array of bulk write operations
  let bulkWriteOps = [];

  for (let i in r) {
    const e = r[i];
    e.REF = e.REF.trim();
    /* As every update operation is different because it depends on the iteration 
    variable, you have to push each element individually */
    bulkWriteOps.push({
        updateOne: {
            'filter': { REF: e.REF },
            'update': e,
            'upsert': true
            // As you are not using the result of the update, you don't need the new: true flag
        }
    })

    if (i % 500 === 0) {
      console.log((i / total) * 100 + "%");
    }
  }
}

if (bulkWriteOps.length) await MyModel.bulkWrite(bulkWriteOps)

run();
在您的情况下,在每次迭代中,您都在等待文档被查询和更新。大容量写操作旨在避免此类情况,并让DB在幕后完成繁重的工作

如果您想更深入地阅读本主题,请看,这里它告诉您有关批处理大小和操作顺序的信息


希望这能在某种程度上帮助您解决您的问题

我曾经为数据库模型迁移做过此类操作,我发现了这一点。bulkWrite在这里确实起到了作用。我要做的是:

const mongoose = require("mongoose");
const { mongoUrl } = require("../config.js");
const MyModel = require("../models/MyModel");

async function run() {
  mongoose.set("useCreateIndex", true);
  await mongoose.connect(mongoUrl, { useNewUrlParser: true });

  const r = [/* */]; // <-- Something with 500k objects

  const total = r.length;
  // Set empty array of bulk write operations
  let bulkWriteOps = [];

  for (let i in r) {
    const e = r[i];
    e.REF = e.REF.trim();
    /* As every update operation is different because it depends on the iteration 
    variable, you have to push each element individually */
    bulkWriteOps.push({
        updateOne: {
            'filter': { REF: e.REF },
            'update': e,
            'upsert': true
            // As you are not using the result of the update, you don't need the new: true flag
        }
    })

    if (i % 500 === 0) {
      console.log((i / total) * 100 + "%");
    }
  }
}

if (bulkWriteOps.length) await MyModel.bulkWrite(bulkWriteOps)

run();
在您的情况下,在每次迭代中,您都在等待文档被查询和更新。大容量写操作旨在避免此类情况,并让DB在幕后完成繁重的工作

如果您想更深入地阅读本主题,请看,这里它告诉您有关批处理大小和操作顺序的信息


希望这能对你的问题有所帮助

你有参考索引吗?否则,数据库将不得不扫描整个集合,以确定是否存在具有相同引用的模型。@AKX Yes,of cou。。。哼完成。很高兴我能帮忙!我相信如果你想要更高的性能,它会更完整,所以你可能想看看它。我提供了一个.bulkWrite的例子,如果你需要的话。你在REF上有索引吗?否则,数据库将不得不扫描整个集合,以确定是否存在具有相同引用的模型。@AKX Yes,of cou。。。哼完成。很高兴我能帮忙!我相信如果你想要更高的性能,它会更完整,所以你可能想看看它。如果需要,我提供了一个.bulkWrite的示例。