【问题标题】:Node + Mongoose, wait for result before savingNode + Mongoose,等待结果再保存
【发布时间】:2017-02-06 17:11:22
【问题描述】:

我实际上是在尝试在我的 mongodb 数据库中保存一条新记录。

   company.save(function(err, company){
        if (err)
            //fail;

    //success
    })

但是,在此操作之前,我想为我的公司添加标签

我的公司架构

var companySchema = new mongoose.Schema({
    name: String,
    accro: String,
    npa: String,
    city: String,
    country: String,
    isverified : Boolean,
    tags: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Tag'  //  réf. tagSchema
    }
    ]
})

如你所见,标签是一个参考,所以我正在检查标签是否已经存在:

for (var i = 0; i < req.body.tags.length; i++) {
        var currentTag = req.body.tags[i];

        Tag.findOne({'label': currentTag }, function(err,t){
            var tag_id = "";

            if(err) res.send(err);

            // if exist
            if (t) {
                console.log("#" + i + " currentTag existe");
                t.use++;
                t.save();
                tag_id = t._id;

            } else {

                console.log("#" + i + " currentTag not existe");
                var tag = new Tag();
                tag.label = currentTag;
                tag.save();
                tag_id = tag._id;
            }

            company.tags.push(tag_id);

        });
    }

但由于 mongoose findOne 函数有一个回调,循环只是保持“循环”,当company.save() 被触发时,公司没有添加任何标签..

需要一些帮助才能使其异步 :) 谢谢

【问题讨论】:

    标签: node.js asynchronous mongoose


    【解决方案1】:

    您无需逐个查找标签。使用 $in 运算符,如下所示:

    Tag.find({'label': {$in: req.body.tags}},function(err,oldTags){
    
    
                if(err) res.send(err);
    var tag_id = '';
                for(var i = 0; i < req.body.tags.length; i++){
                  for(var j = 0; j < oldTags.length; j++){
    
                  if(req.body.tags[i] == oldTags[j].label){
                   oldTags[j].use++;
                   oldTags[j].save(function(err, tag) {
                                    company.tags.push(tag._id);
    
    
    });
                  } else {
                  console.log("#" + i + " currentTag not existe");
                  var tag = new Tag();
                  tag.label = req.body.tags[i];
                  tag.save(function(err, newTag) {
                                    company.tags.push(newTag._id);
    
    
    });
                  }
    
                }
                }
    // HERE SAVE YOUR COMPANY OBJECT
            });
    

    更新

    Tag.find({
        'label': {
            $in: req.body.tags
        }
    }, function(err, oldTags) {
    
        if (err) res.send(err);
        var tags_id = [];
        var db_labels = [];
        var db_ids = [];
        var new_tags = [];
    
        for (var i = 0; i < oldTags.length; i++) {
            db_labels.push(oldTags[i].label);
            db_ids.push(oldTags[i]._id);
        }
    
        for (var i = 0; i < req.body.tags.length; i++) {
            var label = req.body.tags[i].trim().toUpperCase();
            var tag_id = "";
            if (db_labels.indexOf(label) == -1) {
    
                //tag not found
                //var tag = new Tag();
                //tag.label = label;
                new_tags.push({
                        label: label
                    })
                    // tag.save(function(err, newTag) {
                    //     tags_id.push(newTag._id);
                    // });
    
            } else {
    
                //tag found
                tags_id.push(db_ids[db_labels.indexOf(label)]);
    
            }
        }
    
        Tag.collection.insert(new_tags, function(err, data) {
            tags_id = tags_id.concat(data.insertedIds);
            company.tags = tags_id;
            company.save(function(err, company) {
                if (err)
                    res.send(err);
    
                res.json(company);
            })
        });
    });
    

    【讨论】:

    • 那么他应该在哪里写 company.save() ?外面的循环?如果是这样,那么 tag.save() 会在那个时候完成吗?
    • 只需尝试上面的代码并将 save() 放入其中,因为它与其他代码无关。它的异步行为不会影响流程。对于公司标签,将其保存在循环之外。
    • 终于搞定了:双循环并不理想,你可以在这里查看我的代码 :) 非常感谢 $in
    • 代码错误。 tag.save() 不是同步调用。
    • var tag = new Tag(); tag.label = req.body.tags[i];tag.save(); tag_id = tag._id; 将始终导致 tag_id 未定义
    【解决方案2】:

    您要查找的模式是promise.all

    var q = require('q');
    var arr = [];
    for (var i = 0; i < req.body.tags.length; i++) {
        //check if tag exist and if not create 
        var promise = tag.save();
        arr.add(promise) 
    }
    
    
    q.all(arr).then(function(newArr) { //check what comes in newArr and set it in company tags
       company.tags.push(newArr);
       //save company
    });
    

    【讨论】:

    • 嗯,我正在尝试在我的应用程序中使用它,但问题是,要查找标签是否存在,我正在使用 mongoose.find() 并且它是异步的,这意味着tag.save() 在应用程序在数据库中找到标签之前被调用.. --> newArr 为空
    • 没关系。照你演示的做。检查标签是否存在?在该方法 create it if is not existing and in its call back add to promise array 的回调中。同样,如果现有更新它并添加到承诺数组
    • 所以当做出新的承诺时会触发 q.all ?
    • q.all 仅在所有承诺都解决后才会触发。
    【解决方案3】:

    按照@Sachin 的回答:得到这个:

        Tag.find({'label': {$in: req.body.tags}},function(err,oldTags){
    
          if(err) res.send(err);
                    var tags_id = [];
                    var db_labels = [];
                    var db_ids = [];
    
                    for (var i = 0; i < oldTags.length; i++) {
                        db_labels.push( oldTags[i].label );
                        db_ids.push( oldTags[i]._id );
                    }
    
                    for (var i = 0; i < req.body.tags.length; i++) {
                        var label = req.body.tags[i].trim().toUpperCase();
                        var tag_id = "";
                        if ( db_labels.indexOf(label) == -1) {
    
                            //tag not found
                            var tag = new Tag();
                            tag.label = label;
                            tag_id = tag._id;
                            tag.save();
    
                        } else {
    
                            //tag found
                            tag_id = db_ids[db_labels.indexOf(label)];
    
                        }
                        tags_id.push( tag_id )
                    }
    
                    company.tags = tags_id;
                    company.save(function(err, company){
                        if (err)
                            res.send(err);
    
                        res.json(company);
                    })
        });
    

    【讨论】:

    • var tag = new Tag(); tag.label = label; tag_id = tag._id;tag.save(); tag_id 将始终未定义 :-)
    • 不,因为 id 是在您创建对象本身时创建的:D
    猜你喜欢
    • 2020-05-27
    • 1970-01-01
    • 1970-01-01
    • 2018-04-27
    • 2020-07-24
    • 2017-03-18
    • 1970-01-01
    • 1970-01-01
    • 2017-10-30
    相关资源
    最近更新 更多