Подтвердить что ты не робот

В Meteor, как обновить одно поле db при изменении другого поля?

Общий вопрос: в Meteor, какой лучший способ реализовать бизнес-логику, которая запускается всякий раз, когда модель обновляется - например, для обновления зависимых полей или валидации или...

Конкретный пример: я хотел бы добавить поле "slug" в коллекцию списков в примере Meteor todos. Пул должен автоматически обновляться при каждом изменении имени списка.

Вот что у меня есть... Я наблюдаю за каждым изменением в списке, чтобы увидеть, нужно ли его создавать или обновлять его. Это находится в shared 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() как "списки", а client/todos.js подписывается на эту коллекцию.)

Вышеприведенный код, похоже, работает, но как-то не подходит мне. Вопросы:

  • Наблюдает ли коллекция списков, как это, разумный подход? Кажется, что это может быть неэффективным - любое изменение в документе "Списки" инициирует этот код.
  • Должен ли я делать другую (смоделированную) клиентскую версию обновления, или это нормально, чтобы позволить это же обновление Mongo/Minimongo работает на обоих?
  • Нужно ли мне называть listsObserver.stop() в какой-то момент, чтобы распоряжаться наблюдателем? И если да, то когда?

(Я только начинаю работать с Meteor, поэтому, возможно, мои пристрастия к другим средам протекают. Подразумеваемый мета-вопрос здесь, я даже думаю об этой проблеме правильно?)

4b9b3361

Ответ 1

Я бы предложил использовать пакет Collection-Hooks. Он расширяет операции сбора до и после крючков. Это лучше, чем наличие большого количества наблюдений Observes или ObserveChanges, особенно на сервере, где накладные расходы для наблюдений за коллекцией могут быть очень большими.

Это работает как на клиенте, так и на сервере. Если вы реализуете его на клиенте, вам будет полезно обновить локальную коллекцию (компенсацию латентности), и изменение будет перенесено на сервер, поэтому не нужно делать это снова.

Вы также получаете преимущество только в выполнении одной операции MongoDB вместо двух или более таких, которые вы бы наблюдали или наблюдали за изменениями.

Вы можете использовать его так:

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

Ответ 2

Я сделал аналогичную вещь в коде сервера. По существу, этот код в Meteor.methods(), наряду с любыми другими проверками и обновлениями, которые вы хотите сделать в коллекции списков.

Хотя приведенный ниже код выглядит немного грязным и, конечно же, трудно понять с помощью строки, начинающейся с 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}});
     }
   }
});

Ответ 3

Один из способов реализовать это - определить пользовательскую функцию шаблона и запустить ее в изменяющемся шаблоне. Например:

В 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" обновляется, он будет вызывать ваш метод.