3

i try to build a simple chat. User can select another one to talk with it. I use Ember with firebase. I've build my model like firebase example.

This is my simple model. User Model :

import DS from "ember-data";

var user = DS.Model.extend({
    name : DS.attr('string'),
    messages : DS.hasMany("message", {async : true, inverse : 'owner'})
});

export default user;

Message Model :

import DS from "ember-data";

var message = DS.Model.extend({
    date : DS.attr('date'),
    content : DS.attr('string'),
    owner : DS.belongsTo('user', {async : true}),
    target: DS.belongsTo('user', {async : true})
});

export default message;

Emberfire doesn't support 'findQuery' ember-data type search, so how can i retrieve all messages that belong to a conversation? It is the right way to define my model or is there another one? In the ideal case, i would just want retrieve all message with a single request. ( from owner to target and from target to owner)

Scandinave
  • 1,148
  • 1
  • 12
  • 33

1 Answers1

4

If you're sticking with the official emberfire bindings, you can set up three models:

User:

var user = DS.Model.extend({
    name          : DS.attr('string'),
    conversations : DS.hasMany('conversation', { async: true }),
    convos_users  : DS.hasMany('convo_user', { embedded: true })
});

Conversation:

var conversation = DS.Model.extend({
    messages : DS.hasMany('message', { embedded: true })
});

Message:

var message = DS.Model.extend({
    date    : DS.attr('date'),
    content : DS.attr('string'),
    from    : DS.belongsTo('user', { async : true })
});

And then set up the embedded convos_users index:

var convos_users = DS.Model.extend({
    with         : DS.belongsTo('user', {async : true}),
    conversation : DS.belongsTo('conversation', { async: true })
});

So the resulting schema looks something like this in firebase:

{
  'users': {
    'user_1': {
      'name': 'Terrance',
      'conversations': {
        'convo_1': true
      },
      'convo_users': {
        0: {
          'with': 'user_2',
          'conversation': 'convo_1'
        },
        ...
      }
    },
    'user_2': {
      'name': 'Phillip',
      'conversations': {
        'convo_1': true
      },
      'convo_users': {
        0: {
          'with': 'user_1',
          'conversation': 'convo_1'
        },
        ...
      }
    },
    ...
  },

  'conversations': {
    'convo_1': {
      'messages': {
        0: {
          'date': 123456789,
          'content': 'Hey buddy!',
          'from': 'user_1'
        },
        1: {
          'date': 123456789,
          'content': 'Hey guy!',
          'from': 'user_2'
        },
        ...
      }
    }
  }
}

This setup lets you embed messages together in a common conversation thread, so you only retrieve the messages for the conversation you want to see. The 'from' attribute in the message lets you render the user that it came from, and sort the alignment of the chat window, or whatever you're looking to do.

Finally, indexing both the list of conversations the user has ever been in, along with an index of the other user id in the conversation and that conversation's ID. This way, when user A goes to send a message to user B, you can do a computed findBy on the 'user_conversations' index. If a match exists, open the conversation with the conversation ID found, and append the messages to the conversation's embedded message array:

actions: {
  sendMessage: function(msg) {
    var userX = this.current_user.get('convos_users').findBy('with','user_X');

    // No User
    if (!userX) {
      // 1. Create a new Conversation (var myRoom)
      // 2. Save room id to users
      // 3. Save room to your conversations model list
    }

    // Else
    myRoom.messages.pushObject(msg);
    myRoom.save();
  }
}

}

Good luck!

Miles Zimmerman
  • 368
  • 2
  • 8