svasva / meteor-publish-with-relations

Meteor.js SmartPackage to publish associated collections at once.
162 stars 30 forks source link

Foreign key relations in arrays are not reactive #9

Open dradovic opened 11 years ago

dradovic commented 11 years ago

Relations that are defined through arrays are not reactive. For example, in

Meteor.publish("groups", function(userId) {
  return Meteor.publishWithRelations({
    handle: this,
    collection: Groups,
    filter: {
      $or: [
        {
          ownerId: userId
        }, {
          memberIds: userId
        }
      ]
    },
    mappings: [
      {
        key: "memberIds",
        collection: Meteor.users
      }
    ]
  });
});

once loaded, the users collection on the client will not reflect changes in the group.memberIds array.

svasva commented 11 years ago

Thats true, it doesn't observe for foreign key changes. So it looks like a feature request :)

lgandecki commented 11 years ago

It doesn't? I thought that following code was doing just that.

 changed: (id, fields) ->
      _.each fields, (value, key) ->
        changedMappings = _.where(params.mappings, {key: key, reverse: false})
        doMapping(id, fields, changedMappings)

I've made some changes to be able to work with nested arrays of objects (I have a course object, and inside it I have a comments objects, that have userIds in it, so, like


Course = {
    name: something,
    comments: [
        {
            userId: firstUserId,
            comment: "some text"
        }
        {
            userId: secondUserId,
            comment: "different text"
        }
    ]
}

I needed to publish all the users that commented on the course. To make it work

@@ -20,7 +20,10 @@
         mapFilter[mapping.key] = id
       else
         objKey = mapping.key
-        mapFilter._id = obj[mapping.key]
+        if mapping.nestedArray
+            mapFilter._id = _.uniq(_.pluck(obj[mapping.nestedArray], mapping.key))
+        else
+            mapFilter._id = obj[mapping.key]
         if _.isArray(mapFilter._id)
           mapFilter._id = {$in: mapFilter._id}
       _.extend(mapFilter, mapping.filter)
@@ -47,7 +50,9 @@
       doMapping(id, fields, params.mappings)
     changed: (id, fields) ->
       _.each fields, (value, key) ->
-        changedMappings = _.where(params.mappings, {key: key, reverse: false})
+        changedKeyMappings = _.where(params.mappings, {key: key, reverse: false})
+        changedNestedArrayMappings = _.where(params.mappings, {nestedArray: key})
+        changedMappings = changedKeyMappings.concat changedNestedArrayMappings
         doMapping(id, fields, changedMappings)
       pub.changed(collection._name, id, fields)
     removed: (id) ->

Mappings:

mappings: [
    {
        key: "userId",
        nestedArray: "comments",
        collection: Meteor.users
    }
]

My point is - when someone comments on the course I automatically get his info published to my client, if the client is looking at the course comments at the time. I can't think of an collection in my db that would just use the array of ids so I can't double check it, but I'd expect it to work the same way.

dradovic commented 11 years ago

As far as I remember, my issue was rather that adding and removal of new IDs in the array were not reflected (rather than modifications of the existing records). Might be related to #7 (and ultimately to meteor/meteor#944) which was the reason I had to abandon this package anyway.

jwaltz commented 10 years ago

Igandecki, thank you for the code to make foreign keys in a nested array of objects work. I am using your changes currently. Was wondering if you've discovered anything new about this issue?