Meteor和DBRefs

时间:2012-06-28 12:08:16

标签: mongodb meteor

我在Win7(32)中使用meteor 0.3.7并尝试使用2个MongoDB集合创建一个简单的日志系统来存储由DBRef链接的数据。

当前的伪架构是:

    Users {
      username : String,
      password : String,
      created  : Timestamp,
    }

    Logs {
      user_id : DBRef {$id, $ref}
      message : String
    }

我使用服务器方法插入日志,这样我就可以在客户端集合上做一些upsert。

现在我想做一个旧的“左连接”并显示带有嵌入式用户名的最后n个日志的列表。 我不想在用户中嵌入日志,因为最常用的操作是获取最后n个日志。在我看来,嵌入会对性能产生重大影响。

实现这一目标的最佳方法是什么?

接下来,如果可能的话,可以编辑用户名,所有项目都会更改名称

此致

2 个答案:

答案 0 :(得分:2)

玩Cursor.observe回答了我的问题。它可能不是最有效的方法,但解决了我将来解决DBRefs“链接”的问题

因此,对于服务器,我们需要发布一个特殊的集合。一个可以枚举游标并为每个文档搜索相应的DBRef。 请记住,这个实现是硬编码的,应该像UnRefCollection这样的包完成。

服务器端

    CC.Logs = new Meteor.Collection("logs");
    CC.Users = new Meteor.Collection("users");

Meteor.publish('logsAndUsers', function (page, size) {
    var self = this;
    var startup = true;  
    var startupList = [], uniqArr = [];

    page = page || 1;
    size = size || 100;
    var skip = (page - 1) * size;

    var cursor = CC.Logs.find({}, {limit : size, skip : skip});
    var handle = cursor.observe({
        added : function(doc, idx){
            var clone = _.clone(doc);
            var refId = clone.user_id.oid; // showld search DBRefs
            if (startup){
                startupList.push(clone);    
                if (!_.contains(uniqArr, refId))
                    uniqArr.push(refId);
            } else {
                // Clients added logs
                var deref = CC.Users.findOne({_id : refid});
                clone.user = deref;
                self.set('logsAndUsers', clone._id, clone);
                self.flush();
            }
        },
        removed : function(doc, idx){
            self.unset('logsAndUsers', doc._id, _.keys(doc));
            self.flush();
        },
        changed : function(new_document, idx, old_document){
            var set = {};
            _.each(new_document, function (v, k) {
              if (!_.isEqual(v, old_document[k]))
                set[k] = v;
            });
            self.set('logsAndUsers', new_document._id, set);
            var dead_keys = _.difference(_.keys(old_document), _.keys(new_document));
            self.unset('logsAndUsers', new_document._id, dead_keys);
            self.flush();
        },
        moved : function(document, old_index, new_index){
            // Not used
        }
    });

    self.onStop(function(){
        handle.stop();
    });

    //  Deref on first Run
    var derefs = CC.Users.find({_id : {$in : uniqArr} }).fetch();
    _.forEach(startupList, function (item){
        _.forEach(derefs, function(ditems){
            if (item["user_id"].oid === ditems._id){
                item.user = ditems;
                return false;
            }
        });
        self.set('logsAndUsers', item._id, item);
    });
    delete derefs; // Not needed anymore

    startup = false;
    self.complete();
    self.flush();
});

对于每个添加的日志文档,它将搜索用户集合并尝试将缺少的信息添加到日志集合中。 在第一次运行中为日志集合中的每个文档调用添加的函数我创建了一个startupList和一个唯一用户id的数组,因此对于第一次运行它只会查询一次db。最好使用分页机制来加快速度。

客户端

在客户端上,订阅logsAndUsers集合,如果要进行更改,请直接将其添加到Logs集合中。

LogsAndUsers = new Meteor.collection('logsAndUser');
Logs = new Meteor.colection('logs'); // Changes here are observed in the LogsAndUsers collection

Meteor.autosubscribe(function () {
    var page = Session.get('page') || 1;
    Meteor.subscribe('logsAndUsers', page);
});

答案 1 :(得分:0)

为什么不直接也将用户名存储在日志集合中? 然后你可以直接查询它们而无需任何“加入”

如果由于某种原因您需要能够处理该用户名更改,您只需按名称获取用户对象,然后使用{ user_id : user._id }

查询日志