Node.js 检测两个猫鼬查找何时完成

     2023-03-07     61

关键词:

【中文标题】Node.js 检测两个猫鼬查找何时完成【英文标题】:Node.js detect when two mongoose find are finished 【发布时间】:2017-01-21 01:24:27 【问题描述】:

我正在尝试使用 library 使用自动完成功能初始化两个输入。当我加载我的页面时,我会触发一个 Ajax 来初始化两个输入文本。

但我不知道如何检测我的所有 mongoose 查找何时完成。

这是我的服务器端代码:

app.post('/init/autocomplete', function(req, res)
    var autocomplete = 
        companies: [],
        offices: []
    ;

    // Find all companies
    Company.find(, function(err, companies) 
        if (err) throw err;

        companies.forEach(function(company) 
            autocomplete.companies.push(value: company.name)
        );

        console.log('One');
    );

    // Find all offices
    Office.find(, function(err, offices) 
        if (err) throw err;

        offices.forEach(function(office) 
            autocomplete.offices.push(value: office.name)
        );

        console.log('Two');
    );

    console.log('Three');

    // res.json(autocomplete);
);

我知道 find 方法是异步的。这就是为什么我按这个顺序看到我的 console.log() :

Three
One
Two

Company.findOffice.find 完成时,我该如何触发console.log('Three');

我想在最后一个位置看到console.log('Three');

编辑:

我想我可以这样做:

app.post('/init/autocomplete', function(req, res)
    var autocomplete = 
        companies: [],
        offices: []
    ;

    // Find all companies
    Company.find(, function(err, companies) 
        if (err) throw err;

        companies.forEach(function(company) 
            autocomplete.companies.push(value: company.name)
        );

        // Find all offices
        Office.find(, function(err, offices) 
            if (err) throw err;

            offices.forEach(function(office) 
                autocomplete.offices.push(value: office.name)
            );

            res.json(autocomplete);
        );
    );
);

但我不知道这是否是好方法。也许使用 promise 会更好?我愿意接受所有建议。

【问题讨论】:

使用 Promise,用 Promise 可以很轻松的解决并列问题 【参考方案1】:

Mongoose 内置了对 Promise 的支持,这些 Promise 提供了一种干净的方式来等待使用 Promise.all 完成的多个异步查询操作:

// Tell Mongoose to use the native Node.js promise library.
mongoose.Promise = global.Promise;

app.post('/init/autocomplete', function(req, res)
    var autocomplete = 
        companies: [],
        offices: []
    ;

    // Call .exec() on each query without a callback to return its promise.
    Promise.all([Company.find().exec(), Office.find().exec()])
        .then(results => 
            // results is an array of the results of each promise, in order.
            autocomplete.companies = results[0].map(c => (value: c.name));
            autocomplete.offices = results[1].map(o => (value: o.name));
            res.json(autocomplete);
        )
        .catch(err => 
            throw err; // res.sendStatus(500) might be better here.
        );
);

【讨论】:

很好,但是猫鼬如何处理它的内部错误?出现错误时它会中断吗?还是将所有内容返回结果?实际上,在某些情况下,我更愿意收集所有结果,并让客户端处理哪个查询成功或失败 @vdj4y 如果查询失败,则拒绝承诺并调用catch 处理程序。在需要以不同方式处理部分成功的情况下,您不会使用Promise.all。您基本上是在用Promise.all 说“全有或全无”。 我明白了,有时候,它会很好。我认为如果手动创建 Promise,我可以选择 resolve(err) 并立即返回。但这应该是我在其他情况下的首选代码。谢谢 感谢您的回答。这对我的情况来说是个好主意 .map() 比 forEach 有更好的性能?我从来没有见过它,它看起来很不错【参考方案2】:

使用Promise。有一些方法可以控制并联和串联。而且您的代码往往更具可读性。我处理并行的方法是先执行异步部分,然后在收集到结果后执行同步部分。

app.post('/init/autocomplete', function(req, res)
    // Find all companies
    // the query action below is not executed, just return PromiseObject for now
    var findCompanies = new Promise((resolve, reject) => 
      Company.find(, function(err, companies) 
          if (err) reject(err);
          resolve(companies)                   
       );
    )

    // Find all offices
    // the query action below is not executed, just return PromiseObject for now
    var findOffices = new Promise((resolve, reject) => 
      Office.find(, function(err, offices) 
          if (err) reject(err);
          
          resolve(offices)
      );
    )
    
    // this is the execution part, in OOP world, you can think this is main()
    // execute and wait until each action(Promise Object) is complete before finally returning an array.
    return Promise.all([findCompanies, findOffices])
                  .then(array => 
                       console.log(array) // [ [companies] , [offices]  ]
                       //the difficult async part is done, with just few lines
                                                                           
                       console.log(array[0]) // [companies] array of companies
                       console.log(array[1]) // [offices] array of offices
                      
                       // now you can safely manipulate using forEach.
                       // basically, this part is for the synchronous action               
                       
                        var autocomplete = ;

                        array[0].forEach(function(company) 
                            autocomplete.companies.push(value: company.name)
                        );
                        array[1].forEach(function(office) 
                            autocomplete.office.push(value: office.name)
                        );
                       res.json(autocomplete)
                  )
);

上面的代码,findCompanies 和 FindOffices 是 Promise 对象存储在变量中(它还没有执行)。接下来,使用 Promise.all(),我们运行所有的 Promise 对象,它会等到每个动作完成后才最终返回一个数组。

返回的数组包含另外两个数组。这个数组的顺序和你传递给 Promise.all() 的动作顺序是一样的

如果您先找到办公室,然后再找到公司。它将返回 [[offices],[companies]] Promise.all([findOffices, findCompanies]) 将返回 [[offices], [companies]]

反之亦然

Promise.all([findCompanies, findOffices]) 将返回 [[companies], [offices]]

【讨论】:

非常好的答案,谢谢。所以我可以用 array[0].name 在company.name 上做我的 foreach 吗?这个数组将包含我的 mongodb json 对象?并且最好使用 Native Promise 或 bluebird ? array[0] is [companies] ,你可以做 array[0].forEach( (company) => //push to autocomplete ) 数组的序列是你传递给 Promise.all() 的序列,如果你传递 [offices, Companies] 它将返回 [[offices], [companies] ]。反之亦然 我必须删除 return 关键字,因为我有这个错误:var findCompanies = return new Promise(function(resolve, reject)SyntaxError: Unexpected token return。为了创建 forEach 循环,我必须使用 companiesoffices 数组初始化我的自动完成变量,否则循环将停止。 哦,是的,对不起,我忘了它是一个变量而不是一个函数。将更新代码【参考方案3】:

使用 Promises,您将拥有更清晰的代码来维护而不会产生太多开销,使用 Mongoose 您有两个选择。使用本机 Mongoose 承诺,这对于基本用例来说很好。但是 Mongoose 的承诺目前已被弃用,因为会出现警告。

所以要切换到原生 Promises:

// Native JS Promise
mongoose.Promise = global.Promise;

或者到更高级的Bluebird Promise 库:

// Bluebird
mongoose.Promise = require('bluebird');

带有原生 JS 承诺的 MVCE 和 Bluebird 已被注释掉。

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const assert = require('assert');

mongoose.connect("mongodb://localhost:33023/test_1");

// Native JS Promise
mongoose.Promise = global.Promise;

// Bluebird
// mongoose.Promise = require('bluebird');


// Schema creation
var Company = mongoose.model('Company', new Schema(
  name: String
));

var Office = mongoose.model('Office', new Schema(
  name: String
));


var acme = new Company(
  name: 'ACME'
);

var HR = new Office(
  name: 'Human Resources'
);

acme
  .save()
  .then(HR.save());

var query = Company.find();
assert.equal(query.exec().constructor, global.Promise);
// assert.equal(query.exec().constructor, require('bluebird'));

query.exec()
.then(function(results) 
  console.log(results);
)
.then(Office.find()
.then(function(results) 
  console.log(results);
));

Mongoose Promises 的文档。

【讨论】:

Promise.all() 在这种情况下也很有用。 感谢您的回答。我从不在节点 js 中使用 promise,这将是我的第一次。 @vdj4y 的答案和您的答案有两种方法。有什么区别? 基本上Promise.all 在所有承诺都解决后返回一个承诺。如果任何传入的 Promise 被拒绝,所有 Promise 立即以被拒绝的 Promise 的值拒绝,丢弃所有其他 Promise,无论它们是否已解决。所以如果你想要这种行为是要走的路。在我的情况下,您可以处理流程中的拒绝。 另外我使用的是同步方法而不是@vdj4y,它使用了一种异步方法,这对性能有好处,但你会失去对执行流程的控制。一个很好的解释:***.com/questions/28066429/… 在我的情况下,我更喜欢异步。我需要的不是我所有的承诺都是决心。但我记住了你的回答,因为我认为这对我将来真的有帮助。谢谢【参考方案4】:

可以使用你指定的方法,但是对于大量的异步操作,它会导致callback from hell。为了避免这种情况,最好以顺序和有序的方式编写代码。在您的情况下,您可以使用 async 之类的库来实现此目的,因为 mongoose 不会返回 Promise Object。有关异步库的更多信息,您可以参考此链接。

async.series([
    function(callback) 
        // do some stuff ...
        console.log('one');
        callback(null, 'one');
    ,
    function(callback) 
        // do some more stuff ...
        console.log('two');
        callback(null, 'two');
    
],
// optional callback
function(err, results) 
    // results is now equal to ['one', 'two']
    console.log('three');
);

只有在任务一和二完成后才会写入第三个日志。 series 函数一一运行任务。您可以使用eachSeries 并行运行所有任务。

【讨论】:

【参考方案5】:

我对 mongoose 很陌生,但我遇到了类似的问题,我通过使用 cursor() 解决了它

let cursor = Company.find().cursor();
    cursor.on('data', function(doc)
        //do something with doc
    )


    cursor.on('close', function() 
        console.log("done");
    )

【讨论】:

猫鼬在保存前等待查找完成

】猫鼬在保存前等待查找完成【英文标题】:Mongoosewaitingforfindtofinishbeforesaving【发布时间】:2021-01-2203:20:13【问题描述】:我正在尝试将一个新文档保存到MongoDB中,该文档具有对另一个集合的引用,以便获取我使用find的所有引... 查看详情

检测 WKWebView 何时完成加载

】检测WKWebView何时完成加载【英文标题】:DetectwhenWKWebViewisfinishedloading【发布时间】:2017-03-1421:38:55【问题描述】:如何检测我的WKWebView何时完成加载,以便我可以从中获取URL,例如使用委托方法?我为WKWebView实现了委托方法,... 查看详情

通过猫鼬中的两个值查找数据

】通过猫鼬中的两个值查找数据【英文标题】:Finddatabytwovaluesinmongoose【发布时间】:2016-03-3114:58:46【问题描述】:结构是id:12345,userIDs:["1","2","3"]如何在nodejs中编写查询以查找userId是否存在于基于id的文档中?所以我们必须在查... 查看详情

检测 UISlider 何时完成 Xcode

】检测UISlider何时完成Xcode【英文标题】:detectingwhenaUISliderfinishesXcode【发布时间】:2014-11-1415:18:36【问题描述】:我有一个UISlider,它通过设置CGRect中的x值使UIImageView左右移动,使UISlider.value。我想检测滑块何时停止,以便发生... 查看详情

为啥在 Node.js 中使用猫鼬模式

】为啥在Node.js中使用猫鼬模式【英文标题】:WhyusemongooseschemainNode.js为什么在Node.js中使用猫鼬模式【发布时间】:2020-08-1319:17:17【问题描述】:我正在学习Node.js和Mongoose。然后,我遇到了术语模式,它被定义为数据结构、默认... 查看详情

如何检测 UINavigationController 动画何时完成?

】如何检测UINavigationController动画何时完成?【英文标题】:HowtodetectwhenUINavigationControlleranimationhasfinished?【发布时间】:2012-04-1401:24:50【问题描述】:我希望这是一个简单的问题。如果我有一个UINavigationController并且我将一个新的... 查看详情

node.js 的猫鼬外键问题

】node.js的猫鼬外键问题【英文标题】:mongooseforeignkeyproblemwithnode.js【发布时间】:2020-06-0317:41:47【问题描述】:我有3个收藏:constLeaveSchema=newmongoose.Schema(employee:type:mongoose.Schema.Types.ObjectId,ref:\'User\')constUserSchema=newmongoose.S 查看详情

mongoose populate() 方法有啥相反的吗? (猫鼬,node.js,快递)

】mongoosepopulate()方法有啥相反的吗?(猫鼬,node.js,快递)【英文标题】:Isthereanoppositetomongoosepopulate()method?(Mongoose,node.js,express)mongoosepopulate()方法有什么相反的吗?(猫鼬,node.js,快递)【发布时间】:2019-05-1902:50:20【问题描... 查看详情

您如何检测声音文件何时完成?

】您如何检测声音文件何时完成?【英文标题】:Howdoyoudetectwhenasoundfilehasfinished?【发布时间】:2011-11-1403:26:33【问题描述】:我正在广播接收器活动中使用此代码播放声音文件:notification.sound=Uri.parse("android.resource://emad.app/raw/sev... 查看详情

检测 SqlDataAdapter 填充方法何时完成

】检测SqlDataAdapter填充方法何时完成【英文标题】:DetectwhenSqlDataAdapterfillmethodcompletes【发布时间】:2020-04-1120:14:58【问题描述】:我有一个全局SqlDataAdapter,它为多个SqlCommand提供服务。问题有时是SqlDataAdapter填充方法会引发错误... 查看详情

如何按 ID node.js 过滤猫鼬集合

】如何按IDnode.js过滤猫鼬集合【英文标题】:HowtofiltermongoosecollectionbyIdnode.js【发布时间】:2019-01-1214:21:20【问题描述】:假设我有一个像这样的简单猫鼬模式constmongoose=require(\'mongoose\');constSchema=mongoose.Schema;constUserSchema=newSchema(na... 查看详情

Node.js:根据条件渲染猫鼬元素

】Node.js:根据条件渲染猫鼬元素【英文标题】:Node.js:Rendermongooseelementsbasedonconditions【发布时间】:2021-10-0421:47:31【问题描述】:基本上,我正在尝试制作一种电子商务网站,其中包含男性和女性类别以及子类别。我的目标是使... 查看详情

Android:检测何时安装应用程序

】Android:检测何时安装应用程序【英文标题】:Android:detectwhenappisinstalled【发布时间】:2012-07-0819:08:47【问题描述】:我正在尝试使用DownloadManager类从服务器下载Android应用程序,安装它,然后检测安装何时完成。我正在使用两... 查看详情

Android Webview:检测渲染何时完成

】AndroidWebview:检测渲染何时完成【英文标题】:AndroidWebview:Detectwhenrenderingisfinished【发布时间】:2014-01-2620:14:54【问题描述】:我想在加载WebView后对WebView进行快照。但是,返回的位图始终为空,因为即使我使用了onPageFinished,... 查看详情

无法在 node.js 中用猫鼬填充数组

】无法在node.js中用猫鼬填充数组【英文标题】:can\'tpopulatethearraywithmongooseinnode.js【发布时间】:2013-03-3101:51:32【问题描述】:这是我在课程中的架构varCourseSchema=mongoose.Schema(students:[type:ObjectId,ref:\'User\']);varCourseModel=mongoose.model(\'... 查看详情

检测旋转何时完成并移动到新场景

】检测旋转何时完成并移动到新场景【英文标题】:DetectwhenrotationhascompletedandmovetonewScene【发布时间】:2017-04-2404:57:23【问题描述】:我正在尝试在车轮停止旋转时移动到另一个场景。我的代码如下所示。我不知道如何检测速度... 查看详情

在猫鼬中,我如何按日期排序? (node.js)

】在猫鼬中,我如何按日期排序?(node.js)【英文标题】:InMongoose,howdoIsortbydate?(node.js)【发布时间】:2011-08-1502:16:00【问题描述】:假设我在Mongoose中运行此查询:Room.find(,(err,docs)=>).sort(date:-1);这行不通!【问题讨论】:【参考... 查看详情

在猫鼬中,我如何按日期排序? (node.js)

】在猫鼬中,我如何按日期排序?(node.js)【英文标题】:InMongoose,howdoIsortbydate?(node.js)【发布时间】:2011-08-1502:16:00【问题描述】:假设我在Mongoose中运行此查询:Room.find(,(err,docs)=>).sort(date:-1);这行不通!【问题讨论】:【参考... 查看详情