在Meteor中,如何将查找查询的处理结果作为游标发布?

时间:2015-01-04 23:02:08

标签: javascript meteor underscore.js meteor-publications

我正在使用Meteor构建一个简单的消息传递应用程序。我在未读消息中遇到的问题。我想返回一个列表,显示用户名(我不关心这一点,请不要专注于这方面,围绕反应性连接/复合材料等)和来自该用户的最新消息我需要返回的内容因此,在下面的发布功能中,是最新的未读消息,显然只有每个唯一用户ID中的一个。

要做到这一点我试图在我的发布方法中操纵查找查询的结果,但我不清楚如何操纵文档集而不破坏反应性,正如我在目前所展示的那样下面的代码,这是我到目前为止所得到的:

Meteor.publish('unreadmessages', function() {

    if (!this.userId) {
        throw new Meteor.Error('denied', 'not-authorized');
    }

    var messageQuery, messages, userGroupQuery, userGroups;

    var self        = this;
    var user        = Meteor.users.findOne(self.userId);
    var userIdArr   = [self.userId]; // for use where queries require an array
    var contacts    = user.contacts;

    // get groups
    userGroupQuery  = Groups.find({
        $or : [
            { owner   : self.userId },
            { members : self.userId }
        ]
    }, { // Projection to only return the _id field
            fields : { _id:1 }
        }
    );

    userGroups = _.pluck(userGroupQuery.fetch(), '_id'); // create an array of id's

    messages = Messages.find({
        $or : [
            {
                $and : [
                    { participant : self.userId },
                    { userId : { $in : contacts } },
                    { readBy : { $nin : userIdArr } }
                ]
            },
            {
                $and : [
                    { groupId : { $in : userGroups } },
                    { readBy  : { $nin : userIdArr } }
                ]
            },
        ]
    });

     // TODO : also handle groups here
    uniqueMessages = _.uniq(messages.fetch(), function(msg) {
        return msg.userId;
    });

    return uniqueMessages; // obviously an array and not a cursor - meteor errors out.

});

我意识到我的下划线功能当然是使用并确实返回一个数组,而不是我需要的反应光标。我知道一个解决方案就是简单地选择消息ID然后在消息上运行另一个.find,但是有没有其他/更好/更有效/更自然的方式返回结果集我正在寻找的游标?

3 个答案:

答案 0 :(得分:1)

你可以使用observeChanges并使其成为被动的。在added上,您可以添加字段。我正在使用这个神奇的套餐:meteor-publish-composite,它可以节省您的时间。

使用分页,否则你不会享受表演。

答案 1 :(得分:0)

以下代码确实发布了一个反应性游标并且是一个可行的解决方案,但我想我的问题的关键在于是否有更好的方法来操纵第二个Messages.find的结果集仍然发布一个反应光标(我正在考虑光标.forEach或.map,但我不知道如何处理这个问题。)

基本上 - 有更好的方法:

Meteor.publish('unreads', function() {
    if (!this.userId) {
        throw new Meteor.Error('denied', 'not-authorized');
    }

    // setup some vars
    var messageQuery, messages, userGroupQuery, userGroups, uniqeMsgIds;
    var self        = this;
    var user        = Meteor.users.findOne(self.userId);
    var userIdArr   = [self.userId]; // for use where queries require an array
    var contacts    = user.contacts;

    // get groups
    userGroupQuery  = Groups.find({
        $or : [
            { owner   : self.userId },
            { members : self.userId }
        ]
    }, { // Projection to only return the _id field
            fields : { _id:1 }
        }
    );

    // create an array of group id's that belong to the user.
    userGroups = _.pluck(userGroupQuery.fetch(), '_id');

    messages = Messages.find({
        $or : [
            {  // unread direct messages
                $and : [
                    { participant : self.userId },
                    { userId      : { $in : contacts } },
                    { readBy      : { $nin : userIdArr } }
                ]
            },
            {  // unread group messages
                $and : [
                    { groupId : { $in : userGroups } },
                    { readBy  : { $nin : userIdArr } }
                ]
            },
        ]
    }, { sort : { // put newest messages first
            time : -1
        }
    });

     // returns an array of unique documents based on userId or groupId
    uniqueMessages = _.uniq(messages.fetch(), function(msg) {
        if (msg.groupId) {
            return msg.groupId;
        }
        return msg.userId;
    });

    // Get the id's of all the latest unread messages (one per user or group)
    uniqeMsgIds = _.pluck(uniqueMessages, '_id');

    // finally publish a reactive cursor containing one unread message(latest) for each user/group
    return Messages.find({
        _id : { $in : uniqeMsgIds };
    });

});

答案 2 :(得分:0)

继承人最后的工作代码。这确实返回了一个游标,基本上我正在做的是从多个查询/修改中获取结果并将一组id添加到最终的.find查询中。

Meteor.publish('unreads', function() {
    if (!this.userId) {
        throw new Meteor.Error('denied', 'not-authorized');
    }

    // setup some vars
    var messageQuery,
        messages,
        userGroupQuery,
        userGroups,
        uniqeMsgIds;
    var self        = this;
    var user        = Meteor.users.findOne(self.userId);
    var userIdArr   = [self.userId]; // for use where queries require an array
    var contacts    = user.contacts;

    // get groups
    userGroupQuery  = Groups.find({
        $or : [
            { owner : self.userId },
            { members : self.userId }
        ]
    }, { // Projection to only return the _id field
            fields : { _id:1 }
        }
    );

    // create an array of group id's that belong to the user.
    userGroups = _.pluck(userGroupQuery.fetch(), '_id');

    messages = Messages.find({
        $or : [
            {  // unread direct messages
                $and : [
                    { participant : self.userId },
                    { userId : { $in : contacts } },
                    { readBy : { $nin : userIdArr } }
                ]
            },
            {  // unread group messages
                $and : [
                    { groupId : { $in : userGroups } },
                    { readBy : { $nin : userIdArr } }
                ]
            },
        ]
    }, { sort : { // put newest messages first
            time : -1
        }
    });

     // returns an array of unique documents based on userId or groupId
    uniqueMessages = _.uniq(messages.fetch(), function(msg) {
        if (msg.groupId) {
            return msg.groupId;
        }
        return msg.userId;
    });

    /*  Get the id's of all the latest unread messages
    (one per user or group) */
    uniqeMsgIds = _.pluck(uniqueMessages, '_id');

    /*  finally publish a reactive cursor containing
    one unread message(latest) for each user/group */
    return Messages.find({
        _id : { $in : uniqeMsgIds }
    });

});