3

我正在寻找最高效的解决方案,用于根据请求在 Meteor 框架中向客户端发送结构化数据。

问题: 有时,在将数据从数据库发送到客户端之前,您希望添加一些服务器端生成的附加信息,这些信息正在发送到客户端(即许多对象的安全凭证)。该数据可能是时间关键的(即由于过期时间戳),因此不应存储在数据库中。此外,有时无法在客户端处理此数据(即出于安全原因)。在许多情况下,这些数据在结构上与实际数据库数据相关,但也与单个请求非常相关,因为您可能希望将其丢弃并在新请求中重新生成。

你可以(至少在设计上......):

  1. 创建第二个集合,在那里存储和发布与请求相关的数据,接受写入开销,然后在Meteor.myTemplate.destroyed=function(){...}删除数据中再次接受另一个写入开销。

  2. 将每个条目存储在会话变量中,但是您还必须稍后删除它(Meteor.myTemplate.destroyed=function(){...}),这是我现在最喜欢的,但我在存储大对象时遇到了问题。

  3. 将此数据存储在 dom 中(即在隐藏或可见元素的属性或数据字段中)
  4. Meteor.call('method',arguments,callback(){...})通过将适当的存储在argumentsdom 中并使用callback(){...}.

你不能:(按设计!!)

  1. Meteor.publish("name",function(){...})在服务器上使用转换
  2. Meteor.call()在 a 上的转换中使用 a (Template.variable=function(){return collection.find(...)}如果您Meteor.method()在客户端上有对应的猜测结果,也不要使用!)。

同样,我正在寻找的是性能最佳的解决方案。

4

4 回答 4

2

为了解决我关心的转换问题,因为我认为就智能模型做事而不是一堆匿名函数而言,这是一个服务器转换到达客户端的示例(不是响应式的,通过调用,而不是发布,但说明了服务器转换的讨论点)。

你会得到这个:

每个图像都是本地的

数据:LOLCATZ RULZ
  转换:
数据:LOLCATZ RULZ
  转换:

每个图像服务器转换

数据:LOLCATZ RULZ
  变换:XYZ
数据:LOLCATZ RULZ
  变换:XYZ

从:

<template name='moritz'>
    <h3>each image local</h3>
    <dl>
        {{#each images}}
        <dt>data: {{caption}}</dt>
        <dd>transform: {{secretPassword}}</dd>
        {{/each}}
    </dl>

    <h3>each image server transformed</h3>
    <dl>
        {{#each transformed}}
        <dt>data: {{caption}}</dt>
        <dd>transform: {{secretPassword}}</dd>
        {{/each}}
    </dl>
</template>

if (Meteor.isServer) {

    Images = new Meteor.Collection('images', {
        transform: function (doc) {
            doc.secretPassword = 'XYZ'
            return doc
        }
    });

    Images.allow({
        insert: function (userid, doc) {
            return true;
        }
    });

    if (Images.find().count() < 1) {
        Images.insert({ caption: 'LOLCATZ RULZ'});
    }

    Meteor.publish('images', function () {
        return Images.find();
    })

    Meteor.methods({
        'transformed': function() {
            return Images.find().fetch();
        }
    })
}
else {
    Images = new Meteor.Collection('images');

    imageSub = Meteor.subscribe('images');

    Template.moritz.helpers({
        'images': function () {
            console.log(Images.find().count() + ' images')
            return Images.find();
        },
        'transformed': function () {
            // Should be separated, call should be in route for example
            Meteor.call('transformed', function(err,data){
               Session.set('transformed', data);     
                });
            return Session.get('transformed');
        }
    });
}  
于 2013-09-04T18:54:26.873 回答
0

'Mongo collections' 似乎可以很好地回答您的第一行,但后来我读到了一些相互矛盾的想法和结论,我不确定我是否同意。(例如,你为什么不能做这两件事?因为它必须发生在服务器上?)对我来说最令人困惑的说法是:

该数据可能是时间关键的(即由于过期时间戳),因此不应存储在数据库中。

我不明白该结论的假设是什么,但是如果您认为在 dom 中存储数据是合理的,根据上面的第 2 点和第 3 点,您似乎对性能远低于 mongo db 的系统持开放态度。

您知道您可以从服务器发布额外的服务器生成的计算的第二个集合,这些计算是您从数据中动态生成的,并在客户端上将其与数据放在一起。有点像父子关系:当您显示客户端文档时,从动态集合中提取来自服务器的附加数据并将其处理到您的模板中。

于 2013-09-03T11:39:40.227 回答
0

Jim Mack 在这里创建了一个很好的示例,证明了它在 Session 变量中存储数据库数据以及其他“转换”属性的效果如何。不幸的是,这个例子缺乏反应性,并且在 Meteor 的魔法重新渲染后没有执行所需的“转换”。所以我抓住了他很酷的代码并添加了响应性,这是一个运行良好的苗条代码,但在效率方面将优于 Jim Mack 的示例。

大声笑.html

<head>
  <title>lolz</title>
</head>

<body>
  {{>myItems}}
</body>

<template name="myItems">
    <h3>Reactive Item List with additional properties</h3>
    <button id="add">add</button>
    <button id="remove">remove</button>
    <dl>
        {{#each items}}
            <dt>data: {{caption}}</dt>
            <dd>added property: {{anotherProp _id}}</dd>
        {{/each}}
    </dl>
</template>

大声笑.js

items = new Meteor.Collection('Items');

if (Meteor.isServer) {
    items.allow({
    insert: function (userid, doc) {
        return true;
    },
    remove: function(userid,doc){
        return true;
    }
  });
  while(items.find().count()>0){
    items.remove(items.findOne()._id);
  }
  while (items.find().count() < 3) {
        items.insert({caption: 'LOLCATZ RULZ'});
    }
  Meteor.publish('Items', function () {
      return items.find();
  });
  Meteor.methods({
        'getAdditionalProps': function() {
            additionalProps={};
        items.find().forEach(function(doc){
            additionalProps[doc._id]=reverse(doc.caption);
      });
      return additionalProps;
    }
  });

    function reverse(s){ // server side operation, i.e. for security reasons
    return s.split("").reverse().join("");
    };
}

if (Meteor.isClient){
    Meteor.subscribe('Items');

    Meteor.startup(function(){
        getAdditionalProps();
        itemsHandle=items.find().observe({
            added : function(doc){
                getAdditionalProps();
            },
            removed : function(doc){
                getAdditionalProps();
            },
            changed : function(docA,docB){
                getAdditionalProps();
            }
        });
    });

    Template.myItems.rendered=function(){
        console.log(new Date().getTime());
    };

    Template.myItems.items=function(){
        return items.find();
    }

    Template.myItems.anotherProp=function(id){
        return Session.get('additionalProps')[id];
    }

    Template.myItems.events({
        'click #add':function(e,t){
            items.insert({caption: 'LOLCATZ REACTZ'});
        },
        'click #remove':function(e,t){
            items.remove(items.findOne()._id);
        }
    });
}

function getAdditionalProps(){
    setTimeout(function(){
        Meteor.call('getAdditionalProps',function(error,props){
            Session.set('additionalProps',props);
        });
    },0);
}
于 2013-09-05T12:18:38.927 回答
0

看看Meteor Streams,你可以从服务器直接向客户端发送一些东西,而不必在客户端使用集合。

您可以对收到的消息做一些事情(我正在使用来自流星流站点的示例):

客户

chatStream.on('message', function(message) {
    if(message.expiry > new Date()) {
        //Do something with the message (not being read from a collection)
    }
});

即使您这样做是为了不存储它,但要小心简单的工具(Chrome Inspector)可能会进入“网络/Websocket”选项卡(即使它通过 SSL 加密)并看到正在传递的原始数据。

虽然我不确定您的意图,但如果这是为了在任何情况下的安全性,请永远不要相信您从客户端获得的任何数据。

于 2013-09-03T08:21:29.213 回答