【问题标题】:Wait for mongo writes before returning from a find在从查找返回之前等待 mongo 写入
【发布时间】:2017-12-07 16:18:02
【问题描述】:

我想要一个 store js 对象来管理一个 mongodb 集合并表现得像这样:

store.insert(thing); // called from a pubsub system that don't wait the insert to finish

store.get(); // returns a promise that resolves to the things in the collection
// even if called immediately after insert it must contain the last thing inserted

我是这样手动实现的:

let inserts = 0;
let afterInserts = [];

const checkInsertsFinished = () => {
  if (inserts === 0) {
    afterInserts.forEach(resolve => resolve());
    afterInserts = [];
  }
};

const decrementInserts = () => {
  inserts -= 1;
  checkInsertsFinished();
};

const insertsFinished = () =>
  new Promise((resolve) => {
    afterInserts.push(resolve);
    checkInsertsFinished();
  });

const insert = (thing) => {
  inserts += 1;
  db.collection('mycollection').insertOne(thing).then(decrementInserts);
};

const get = async () => {
  await insertsFinished(); // if there are inserts happening, wait for them to finish
  return db.collection('mycollection').find({}).toArray();
};

return { insert, get };

我想有更多的标准方法可以实现这一点,但我想念查找库或内置功能的词汇......你会怎么做?

感谢您的建议。

【问题讨论】:

  • mongodb.github.io/node-mongodb-native/2.1/api/… 您可以使用插入文档的 id,如果最新插入的 id 不是最新的 get 则您丢失了一些文档并尝试再次递归调用 get。不过,这取决于您期望的文档数量,如果按 id 排序,它应该是高性能的。
  • 我认为它不起作用:如果我调用insert 然后立即调用getfind 可以比insertOne 返回更快,我不会将它与 id 进行比较由上一次插入产生。
  • 更新了答案,里面有很多错误,但认为应该这样做。关键是 insert 在运行时永远不能被调用,但可以在你做 db.collection('mycollection').find({}).toArray( 时被调用,所以你可以将本地启动设置为共享 startGetting 并稍后检查引用相等性(查看 insert 是否取消引用 startGetting ) 在 JS 中{}!=={}

标签: javascript node.js mongodb asynchronous


【解决方案1】:

JavaScript 是单线程的,您编写的任何代码都不能同时在多个线程上运行,因此您应该可以这样做:

let inserting = Promise.resolve(),
startGetting={};

const insert = (thing) => {
  startGetting={};//de-reference startGetting
  inserting = db.collection('mycollection').insertOne(thing)
  return inserting;
};

const get = () => {
  const rec = () =>
    inserting.then(
      _ =>
        new Promise(
          (resolve,reject)=>{
            //the next op is truely async (although I wonder why no promise),
            //  someone can insert while this is completing
            const start=startGetting;
            db.collection('mycollection').find({}).toArray(
              (err,results)=>
                err
                  ? reject(err)
                  //inserting could have been set to tby the time
                  //  this completed (in theory) so use startGetting reference equality
                  : startGetting === start
                    ? resolve(results)//while getting nobody inserted
                    : resolve(rec())
          )
        })
    );
  return rec();
};

return { insert, get };

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-29
    • 2020-04-09
    • 1970-01-01
    相关资源
    最近更新 更多