Meteor:如何发布依赖于其他集合的游标的游标

时间:2013-12-29 13:47:50

标签: javascript mongodb meteor

我的Meteor项目中有以下数据结构:
- 具有属于用户(作者)的一组list-id的用户
- 实际包含列表中所有数据的列表

现在我正在尝试将用户的所有列表发布到客户端。这是一个简单的例子:

   
if (Meteor.isClient) {
    Lists = new Meteor.Collection("lists");

    Deps.autorun(function() {
        Meteor.subscribe("lists");
    });

  Template.hello.greeting = function () {
    return "Test";
  };

  Template.hello.events({
    'click input' : function () {
      if (typeof console !== 'undefined')
        console.log(Lists.find());
    }
  });
}

if (Meteor.isServer) {
    Lists = new Meteor.Collection("lists");

    Meteor.startup(function () {
        if ( Meteor.users.find().count() === 0 ) {
               Accounts.createUser({        //create new user
                   username: 'test',
                   email: 'test@test.com',
                   password: 'test'
               });

               //add list to Lists and id of the list to user
               var user = Meteor.users.findOne({'emails.address' : 'test@test.com', username : 'test'});
               var listid = new Meteor.Collection.ObjectID().valueOf();
               Meteor.users.update(user._id, {$addToSet : {lists : listid}});
               Lists.insert({_id : listid, data : 'content'});
        }
     });


    Meteor.publish("lists", function(){
        var UserListIdsCursor = Meteor.users.find({_id: this.userId}, {limit: 1}).lists;
        if(UserListIdsCursor!=undefined){
            var UserListIds = UserListIdsCursor.fetch();

            return Lists.find({_id : { $in : UserListIds}});
        }
    });

    Meteor.publish("mylists", function(){
        return Meteor.users.find({_id: this.userId}, {limit: 1}).lists;
    });


//at the moment everything is allowed
Lists.allow({
    insert : function(userID)
    {
        return true;
    },
    update : function(userID)
    {
        return true;
    },
    remove : function(userID)
    {
        return true;
    }
});

}

但是发布列表无法正常运行。任何想法如何解决这一问题?我也发布“mylists”以保证用户可以访问“list”字段。

3 个答案:

答案 0 :(得分:3)

解决方案

Lists = new Meteor.Collection('lists');

if (Meteor.isClient) {
  Tracker.autorun(function() {
    if (Meteor.userId()) {
      Meteor.subscribe('lists');
      Meteor.subscribe('myLists');
    }
  });
}

if (Meteor.isServer) {
  Meteor.startup(function() {
    if (Meteor.users.find().count() === 0) {
      var user = {
        username: 'test',
        email: 'test@test.com',
        password: 'test'
      };

      var userId = Accounts.createUser(user);
      var listId = Lists.insert({data: 'content'});
      Meteor.users.update(userId, {
        $addToSet: {lists: listId}
      });
    }
  });

  Meteor.publish('lists', function() {
    check(this.userId, String);
    var lists = Meteor.users.findOne(this.userId).lists;
    return Lists.find({_id: {$in: lists}});
  });

  Meteor.publish('myLists', function() {
    check(this.userId, String);
    return Meteor.users.find(this.userId, {fields: {lists: 1}});
  });
}

更改

  1. 在客户端和服务器之外声明Lists集合(无需声明两次)。
  2. 确保用户在订阅时已登录。 (表现提升)。
  3. 插入测试用户时,请使用所有插入函数返回id(减少代码)的事实。
  4. 确保用户在发布时登录。
  5. 简化lists发布功能。
  6. 修正myLists发布功能。发布需要返回游标,游标数组或虚假值。您无法返回一组id(此代码无论如何都无法访问,因为您需要执行fetchfindOne)。重要说明 - 这将发布另一个具有lists字段的用户文档。在客户端上,它将与现有用户文档合并,因此只有登录用户才能拥有lists。如果您希望所有用户都在客户端上拥有该字段,那么我建议您只将其添加到用户配置文件中。
  7. 警告:在编写本文时,如果附加了其他列表项,则不会发布它们,因为lists发布功能只会在用户登录时重新运行。要使其正常工作,您需要reactive join

答案 1 :(得分:2)

这里真正的问题是架构。

不要存储“此用户拥有这些列表”,例如,针对用户集合。存储“此列表归该用户所有”

通过更改您的示例以在每个ownerId上添加List字段,然后发布变得容易 - 并且被动反应。

它还消除了对myLists发布的需求,因为您只需查询客户端的列表。

修改:如果您的架构在每个userIds上都包含List字段,那么对于非所有者来说,发布也是微不足道的。

解决方案

Lists = new Meteor.Collection('lists');

if (Meteor.isClient) {
  Deps.autorun(function() {
    if (Meteor.userId()) {
      Meteor.subscribe('lists.owner');
      Meteor.subscribe('lists.user');
    }
  });
}

if (Meteor.isServer) {
  Lists._ensureIndex('userIds');
  Lists._ensureIndex('ownerId');

  Meteor.startup(function() {
    if (Meteor.users.find().count() === 0) {
      var user = {
        username: 'test',
        email: 'test@test.com',
        password: 'test'
      };

      var userId = Accounts.createUser(user);
      var listId = Lists.insert({data: 'content', ownerId: userId});
    }
  });

  //XX- Oplog tailing in 0.7 doesn't support $ operators - split into two publications -
  //      or change the schema to include the ownerId in the userIds list
  Meteor.publish('lists.user', function() {
    check(this.userId, String);
    return Lists.find({userIds: this.userId});
  });
  Meteor.publish('lists.owner', function() {
    check(this.userId, String);
    return Lists.find({ownerId: this.userId});
  });
}

答案 2 :(得分:0)

Meteor.users.find()返回许多项目的游标,但您尝试使用

访问.lists
Meteor.users.find({_id: this.userId}, {limit: 1}).lists;

您需要改为使用findOne。

Meteor.users.findOne({_id: this.userId}).lists;

此外,您在存储在用户集合中的阵列上运行.fetch()。如果这是._id字段数组,则不需要提取。

你不能在你的第二次发布中做.lists,因为它必须检查一个光标列出客户端,所以只能使用Meteor.users.find(..),因为你只能发布游标