I have two collections. One is called Posts and the other is called Categories. In the Posts collection, are individual posts which have an id. Shown in the picture as id: 1291,
for this particular post, which is an integer, not a string.
The second collection is the Categories collection which contains the categories each of the posts belong to, most importantly, within each category in the Categories collection is an array of the posts that belong to that category. Pay attention to posts.ID
which in this case is ID: 1291,
This ID is the post id in the Posts collection
posts
that belong to
that category but with few post objects I can utilise.I have a flow that goes like this.
The user scrolls through a list of categories and clicks on a category from the Categories collection with the goal of viewing the posts within that category.
<template name="category">
{{#each categories}}
<span class="title"><a href="/category/{{_id}}">{{name}}</a></span>
{{/each}}
</template>
As it stands, When the user performs this action, they view the posts that are already in category that belongs to the Categories collection (remember the posts array within the category collection) like this
Template.singleCategory.helpers({
categories() {
var id = FlowRouter.getParam('_id');
return Categories.find({
_id: id
}, {
sort: {
timestamp: 1
},
limit: 100
});
}
});
But these posts in the Categories collection do not have certain key objects found in the Posts collection, plus I want to get rid on the posts in the categories.
Instead of using these posts found in the Categories collection, I would like to use the posts found in the Posts collection and I would like to create the relationship using the similar Ids they share. So when a user clicks on a category, the posts they should see should come from the Posts collection, linked by the post ID
in the Categories collection which is identical to the post id
in the Posts collection.
Here is the code. I'm trying to say the following:
In this single category being viewed by the user after they clicked it from the list of other categories, do not show the posts embedded in the Categories collection, Instead, return the Posts collection. In this Posts collection, find each
post id
, then match it toID
fromcategory.posts
within the Categories collection, then Show the objects from Posts collection, notcategory.posts
.
Template.singleCategory.helpers({
posts(){
return Posts.find({ ID: {$in: this.posts }});
}
});
However, I cannot seem to get it to work. I'm getting the error
Exception in template helper: Error: $in needs an array
the posts in the category collection are an array.
how can I solve this?
Building on the code in the answer section I had to treat category.posts so its an array. I'm getting the results I want, well, to an extent, some posts are not coming through. I wonder, could this code be better?
Template.Category.helpers({
categories(){
var id = FlowRouter.getParam('_id');
//create a variable with the correct category by id
var category = Category.findOne(id, {
sort: {
timestamp: 1
},
limit: 100
});
console.log(category);
//target ID within posts
var postArray = category.posts;
console.log(postArray);
//treat the object, clean it up to prepare it for becoming an array
var postArrayStr = JSON.stringify(postArray).replace(/ID/g, '').replace(/\[|\]/g, '').replace(/""/g, '').replace(/:/g, '').replace(/\{|\}/gi, '');
//create an array
var idsArray = postArrayStr.split(',').map(function(item) {
return parseInt(item, 10);
});
//match it to posts id
var matchi = Posts.find({
id: {
$in: idsArray
}
}).fetch();
//
console.log(matchi);
//return it
return matchi;
}
});
What I would do is having in the category collection an array with just the post mongo's _id field (which is unique).
Then in the helper you can query the post collection to return all the posts with those ids.
So it would be something like this:
Template.singleCategory.helpers({
posts(){
var id = FlowRouter.getParam('_id');
var category = Category.findOne(id, {sort: {timestamp: 1},limit: 100 })
var postArray = category.posts
// example --> ["rCBWsKLCAWghBRJg4", "yMDtnDSo43ZDEcqpu", "cQeJntQtvwiHpgdZ9"]
return Posts.find( {_id: {$in: postArray}});
// it will return an array oj objects where each object is a post from the posts collection : [Object, Object, Object]
}
});
There are better way to do it but I think this solution may fix your problem without change too many things