首页 文章

在Meteor中,如何在另一个字段更改时更新一个数据库字段?

提问于
浏览
11

一般问题:在Meteor中,实现在更新模型时触发的业务逻辑的最佳方式是什么 - 例如,用于更新依赖字段或验证或...

具体示例:我想在Meteor todos example中的Lists集合中添加"slug"字段 . 每当更改列表名称时,slug都需要自动更新 .

在这里's what I'已经...我正在观察列表的每个更改,看看是否需要创建/更新其slug . 这是在共享的models.js中(运行服务器和客户端,以获得延迟补偿的好处):

// Lists -- {name: String}
Lists = new Meteor.Collection("lists");

var listsObserver = Lists.find().observe({
    added: updateSlug,
    changed: updateSlug
});

function updateSlug(doc, idx) {
    var slug = (doc.name || '').replace(/\W+/g, '-').toLowerCase();
    if (slug !== doc.slug) {
        console.log("Updating slug for '" + doc.name + "' to " + slug);
        Lists.update(doc._id, {$set: {slug: slug}});
    }
}

(和原始的todos示例一样,server / publish.js将所有 Lists.find() 发布为"lists",client / todos.js订阅该集合 . )

上面的代码似乎有效,但不知何故对我来说不太合适 . 问题:

  • 这样观察列表集是一种合理的方法吗?它似乎效率低下 - 对Lists文档的任何更改都将触发此代码 .

  • 我应该在客户端进行不同的(模拟)更新,还是可以在两者上运行相同的Mongo / Minimongo更新?

  • 我是否需要在某个时候召唤 listsObserver.stop() 来处置观察者?若然,何时?

(我刚刚开始使用Meteor,所以也许我在其他环境中的偏见正在泄漏 . 这里隐含的元问题是,我是否正在以正确的方式思考这个问题?)

3 回答

  • 11

    我建议使用Collection-Hooks包 . 它扩展了钩子前后的收集操作 . 这比拥有大量Observes或ObserveChanges更好,特别是在收集观察的开销可能变得非常大的服务器上 .

    这适用于客户端和服务器 . 如果您在客户端上实现它,您将获得更新本地集合(延迟补偿)的好处,并且更改将被推送到服务器,因此无需再次执行此操作 .

    您还可以获得仅执行一次MongoDB操作而不是两次或更多操作的好处,就像使用observes或observeChanges一样 .

    您可以像这样使用它:

    var beforeInsertSlug = function(userId, doc) {
        var slug = (doc.name || '').replace(/\W+/g, '-').toLowerCase();
        if (slug !== doc.slug) {
            console.log("Updating slug for '" + doc.name + "' to " + slug);
            doc.slug = slug;
        }
    };
    
    var beforeUpdateSlug = function(userId, doc, fieldNames, modifier, options){
        if(modifier && modifier.$set && modifier.$set.doc && _.isString(modifier.$set.doc.name)){
            var slug = (modifier.$set.doc.name || '').replace(/\W+/g, '-').toLowerCase();
            if (slug !== doc.slug) {
                console.log("Updating slug for '" + modifier.$set.doc.name + "' to " + slug);
                modifier.$set.doc.slug = slug;
            }
        }
    
    };
    
    Lists.before.insert(beforeInsertSlug);
    
    Lists.before.update(beforeUpdateSlug);
    

    你可以在这里找到包裹:https://atmospherejs.com/matb33/collection-hooks

  • 1

    我在服务器代码中做了类似的事情 . 基本上将此代码放在Meteor.methods()中,以及您希望对Lists Collection进行的任何其他检查和更新 .

    虽然下面的代码看起来有点混乱,但是以var slug开头的行很难理解:

    Meteor.methods({
       myupdate: function (doc) {
    
         var slug = (doc.name || '').replace(/\W+/g, '-').toLowerCase();
    
         if (slug !== doc.slug) {
            console.log("Updating slug for '" + doc.name + "' to " + slug);
            Lists.update(doc._id, {$set: {slug: slug}});
         }
       }
    });
    
  • 0

    实现此目的的一种方法是定义自定义模板函数并在正在更改的模板中触发它 . 例如:

    在client.js中

    Template.myTemplate.custom_function_to_update = function() {
        // do my update code.  i.e. MyCollections.Update(...);
    }
    

    在带有模板的html文件中

    <template name="myTemplate">
        <!-- Normal template code -->
        {{ custom_function_to_update }}
    </template>
    

    每次模板“myTemplate”更新时,它都会调用您的方法 .

相关问题