简体   繁体   中英

Meteor: How to return only one entry for each value from collection

I am currently working on a Meteor application that also has a chat functionality.

I want to have a list of all conversations that show the most recent message in each conversation. (Similar to Sample of a basic conversation overview )

Let's say I have a collection Messages with a variable conversationId . New messages get assigned a new conversationId and any replies will get assigned the conversationId of the first message.

To achieve this conversation overview, my question is, how do I return from my collection only the most recent entry for each conversationId?

This is where I am stuck:

Template.tabsTwo.helpers({
  messages: function () {

    //to retrieve all messages from the logged in user, then retrieve the conversationIDs and drop duplicates
    var userMessages = Messages.find({senderId: Meteor.userId()}, {sort: {date_created: -1, subject: -1}});

    var userConversationIds = userMessages.map((function(a) {
      return a.conversationId;
    }));

    var uniqueConversationIDs = [];

    $.each(userConversationIds, function(i, el){
        if($.inArray(el, uniqueConversationIDs) === -1) uniqueConversationIDs.push(el);
    });

    return Messages.find({conversationId: {$in:uniqueConversationIDs}}, {sort: {date_created: -1}});
  }
});

This still gives me back all messages. I am asking myself right now if I can modify this query to make it work or if I need to approach this differently (eg do a loop and a .findOne query)?

(I have tried many things and searched for answers in the docs and SO but have troubles getting this right. Any help would be greatly appreciated.)

Your initial solution doesn't work because you are getting a list of conversation ids, and then undoing all the work you did by finding all of the messages for those conversations.

One approach, is to fetch all of the messages and group them by conversation, then select the most recent one in each grouping. Here's one such solution:

// Fetch this user's messages.
var userMessages = Messages
  .find({senderId: Meteor.userId()})
  .fetch();

var firstMessages = _.chain(userMessages)
  // Group all of the messages by conversation.
  .groupBy('conversationId')
  .map(function(messages) {
    // For each message in this conversation's messages, choose the
    // first one by date.
    return _.chain(messages)
      .sortBy(function(message) {return -message.created_at;})
      .first()
      .value();
  }).value();

return firstMessages;

firstMessages is an array of message documents containing the first message added by the current user in each conversation he/she participated in. You can just return that value from your helper, but If you'd prefer to return a cursor, just add the following:

var messageIds = _.pluck(userMessages, '_id');
return Messages.find({_id: {$in: messageIds}});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM