Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Many to many relationship is not queried correctly #586

Closed
charlesfries opened this issue Jul 16, 2019 · 4 comments
Closed

Many to many relationship is not queried correctly #586

charlesfries opened this issue Jul 16, 2019 · 4 comments

Comments

@charlesfries
Copy link

charlesfries commented Jul 16, 2019

DEBUG: -------------------------------
DEBUG: Ember      : 3.10.2
DEBUG: Ember Data : 3.9.1
DEBUG: jQuery     : 3.4.1
DEBUG: EmberFire  : 3.0.0-rc.3
DEBUG: Firebase   : 6.2.4
DEBUG: -------------------------------

I have 2 models with a many-to-many relationship.

models/club

import DS from 'ember-data';
const { Model, attr, hasMany } = DS;

export default Model.extend({
  members: hasMany('member'),
  title: attr('string')
});

models/member

import DS from 'ember-data';
const { Model, attr, hasMany } = DS;

export default Model.extend({
  clubs: hasMany('club'),
  name: attr('string')
});

First I make some example data. I create a club, save it, create a member, save it, and finally update club.members with the saved member and save the club again.

this.store.createRecord('club', { title: 'My Club' }).save().then(club => {
  let member = this.store.createRecord('member', { name: 'Bob' });
  member.clubs.pushObject(club);
  member.save().then(savedMember => {
    club.members.pushObject(savedMember);
    club.save()
  });
});

This yields the following in Firebase:

{
  clubs: {
    kSgSyqzFv3DPyXcvAOwe: {
      title: "My Club",
      members: ["LhOmwWMuynIuCMOLE3K5"]
  },
  members: {
    LhOmwWMuynIuCMOLE3K5: {
      name: "Bob",
      clubs: ["kSgSyqzFv3DPyXcvAOwe"]
  }
}

Everything is working fine at this point. However, when I go to find the created club and read its members property, the result is always an empty array.

this.store.findRecord('club', 'kSgSyqzFv3DPyXcvAOwe').then(club => {
    club.get('members').then(members => {
        console.log(members.firstObject); // always undefined
    });
});

I would expect to see an array of member objects after that second promise fulfillment. What I am doing wrong?

@charlesfries charlesfries changed the title Many to many relationship is not quereied Many to many relationship is not queried correctly Jul 16, 2019
@conormag
Copy link

Any solution to this may depend on whether or not you are using the RTDB adapter or the firestore adapter, although I suspect for many to many relationships its the same issue.

for the firestore adapter it appears to me that many to many is not explicitly handled and in your case above club.get('members') is formulating a query equivalent to { query: 'member', where: ['club', ''==", club.id]}. You can check this by passing a function to your hasMany and checking the constructed query, something like

export default Model.extend({
  members: hasMany('member', {query: ref => {
    console.log(ref);
    return ref;
 }}),
  title: attr('string')
});

My plan, which seems to work reasonably well so far (early days), is to create an additional 'join table' collection and work through that

i.e a collection called clubMembers with a club field and a member field which are the ids of the club and member. I am also explicitly setting the document id as <member.id>_<club.id> - i'm doing this as in my security rules I need to be able to formulate a document id within certain rules so if I need to make sure that only an existing member can add another member then I'm going to have a rule with something like this in it:

exists(path('/databases/' + database + '/documents/clubMembers/' + request.auth.uid + '_' + resource.data.club))

then, in my models I have
clubMembers: hasMany('clubMember') on each side. The adapter forms the correct queries and I can reference club.clubmembers.member etc

Interested to hear what others are doing...

@jamesdaniels
Copy link
Contributor

many-many is not supported with the current design

@charlesfries
Copy link
Author

#596

@chadRoberge
Copy link

I have adjusted the findHasMany class in the adapter for firestore, and I created my own relationship option of ManytoMany. Seems to work for me.

emberfire/addon/adapters/firestore.js

findHasMany(store, snapshot, url, relationship) {
    const adapter = store.adapterFor(relationship.type); // TODO fix types
    if (adapter !== this) {
      return adapter.findHasMany(store, snapshot, url, relationship);
    } else if (relationship.options.subcollection) {
      return docReference(this, relationship.parentModelName, snapshot.id).then(doc => queryDocs(doc.collection(collectionNameForType(relationship.type)), relationship.options.query));
    } else {      
      return rootCollection(this, relationship.type).then(collection => {       
        if (relationship.options.relationship === 'ManytoMany') {         
          return queryDocs(collection.where(pluralize(camelize(relationship.parentModelName)), 'array-contains', snapshot.id), relationship.options.query);
        } else {          
          return queryDocs(collection.where(camelize(relationship.parentModelName), '==', snapshot.id), relationship.options.query);
        }
      });
    }
  }

and in my model i would have...

parcelPids: hasMany('parcel-pid', { async: true, relationship: 'ManytoMany' })

downside obviously is saving references in each model.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants