3

I am working to solve a problem not dissimilar to the discussion present at the following blog post. This is wishing to publish two related data sets in Meteor, with a 'reactive join' on the server side.

https://www.discovermeteor.com/blog/reactive-joins-in-meteor/

Unfortunately for me, however, the related collection I wish to join to, will not be joined using the "_id" field, but using another field. Normally in mongo and meteor I would create a 'filter' block where I could specify this query. However, as far as I can tell in the PWR package, there is an implicit assumption to join on '_id'.

If you review the example given on the 'publish-with-relations' github page (see below) you can see that both posts and comments are being joined to the Meteor.users '_id' field. But what if we needed to join to the Meteor.users 'address' field ?

https://github.com/svasva/meteor-publish-with-relations

In the short term I have specified my query 'upside down' (as luckily I m able to use the _id field when doing a reverse join), but I suspect this will result in an inefficient query as the datasets grow, so would rather be able to do a join in the direction planned.

The two collections we are joining can be thought of as like a conversation topic/header record, and a conversation message collection (i.e. one entry in the collection for each message in the conversation).

The conversation topic in my solution is using the _id field to join, the conversation messages have a "conversationKey" field to join with.

The following call works, but this is querying from the messages to the conversation, instead of vice versa, which would be more natural.

Meteor.publishWithRelations({
  handle: this,
  collection: conversationMessages,
  filter: { "conversationKey" : requestedKey },
  options : {sort: {msgTime: -1}},
  mappings: [{
    //reverse: true,
    key: 'conversationKey',
    collection: conversationTopics,
    filter: { startTime: { $gt : (new Date().getTime() - aLongTimeAgo ) }  },
    options: {
      sort: { createdAt: -1 }
    },
  }]
});
MultiMat
  • 93
  • 8
  • Please add the following to your question: the relevant schema information for the collections you wish to join, how you wish to join them, and the code you have written so far. – David Weldon Nov 24 '14 at 18:10
  • I've done that now. The more general question however, would be if this could be done, should the join not be on the '_id' field on either side. – MultiMat Nov 25 '14 at 12:15

2 Answers2

1

Can you do a join without an _id?

No, not with PWR. Joining with a foreign key which is the id in another table/collection is nearly always how relational data is queried. PWR is making that assumption to reduce the complexity of an already tricky implementation.

How can this publish be improved?

You don't actually need a reactive join here because one query does not depend on the result of another. It would if each conversation topic held an array of conversation message ids. Because both collections can be queried independently, you can return an array of cursors instead:

Meteor.publish('conversations', function(requestedKey) {
  check(requestedKey, String);
  var aLongTimeAgo = 864000000;
  var filter = {startTime: {$gt: new Date().getTime() - aLongTimeAgo}};

  return [
    conversationMessages.find({conversationKey: requestedKey}),
    conversationTopics.find(requestedKey, {filter: filter})
  ];
});

Notes

  • Sorting in your publish function isn't useful unless you are using a limit.

  • Be sure to use a forked version of PWR like this one which includes Tom's memory leak fix.

  • Instead of conversationKey I would call it conversationTopicId to be more clear.

Community
  • 1
  • 1
David Weldon
  • 63,632
  • 11
  • 148
  • 146
  • Thanks for your response. I will switch to Tom's PWR fork. I do need to use a join in my case, because we do want to limit the results (limited number of conversationTopics not conversationMessages). – MultiMat Nov 27 '14 at 11:08
  • Yes that makes more sense; the limit was a critical piece of information. So given that, what does an acceptable answer to this question look like? Should I invert the original query? – David Weldon Nov 27 '14 at 15:06
0

I think this could be now much easier solved with the reactive-publish package (I am one of authors). You can make any query now inside an autorun and then use the results of that to publish the query you want to push to the client. I would write you an example code, but I do not really understand what exactly do you need. For example, you mention you would like to limit topics, but you do not explain why would they be limited if you are providing requestedKey which is an ID of a document anyway? So only one result is available?

Mitar
  • 6,756
  • 5
  • 54
  • 86