Sorting a list of items into different categories - mongodb

Imagine a site that lists different articles with different subjects, and you as a user can mark your favorite articles to read later. Favorited articles get saved and displayed in your personal little space on this site like this:
Movies
Upcoming summer blockbusters
Will there never be a end of Superheroes?
Are romcoms dead?
Science
Bezos or Musk, who will reach Mars first?
Philosophy
How can mirrors be real if our eyes aren't real?
Etc, etc.
I have saved each article in the database with the following fields:
{
articleName: "Upcoming summer blockbusters",
subject: "Movies",
link: //link to the article
}
Then when a user favorites one I simply duplicate it into his own collection in the database.
Then comes the problems...
I could iterate through his articles and print them out on his user page like so:
<ul>
{{#each articles}}
<heading>{{subject}}</heading> //how do I avoid duplicates?
<li>{{articleName}}</li>
{{/each}}
</ul>
This, however, would duplicate the subjects that are shared across multiple articles.
I could iterate through the subjects only (making them into an array that checks for duplicates, for instance) and print them out:
<ul>
{{#each subjects}}
<heading>{{this}}</heading>
<li>{{../articleName}}</li> //how do I print the correct one?
{{/each}}
</ul>
But this way would be completely broken, since the articles wouldn't show up under the correct subject headings...
How should I proceed?

Actually I think you should store favorite articles only, the way you did. It will be way simpler to handle cases like article deletions. Just parse the articles in a helper function, and you should get the same result:
favArticlesBySubjects: function () {
var favArticles = Meteor.user().profile.favArticles;
var articlesBySubject = [];
favArticles.forEach(function (article) {
var index = _.findIndex(articlesBySubject, function (obj) {
return obj.subject === article.subject;
});
if (index < 0)
articlesBySubject.push({subject: article.subject, articles:[article]});
else
articlesBySubject[index].articles.push(article);
};
return articlesBySubject;
}
This way, you can display your favorite articles using :
{{#each favArticlesBySubjects}}
<heading>{{subject}}</heading>
<ul>
{{#each articles}}
<li>{{articleName}}</li>
{{/each}}
</ul>
{{/each}}

Related

Firebase- How to retrieve specific set of data using angularfire

I am very new to firebase, and angularfire, not able to find examples with new angularfire and firebase api, most of the examples used old apis,
firebase -3.2.0
angularfire -2.0.1
Here are two cases:
Case 1:
I want to retrieve only record having name:"amitabh" with email and uid,
here is what I have done
function getUserName(uid){
return firebaseDataService.users.startAt("amitabh")
.endAt("amitabh")
.once('value', function(snap) {
console.log('matching name address', snap.val())
});
}
but its returning whole users list,not that one particular record.
Case 2:
How to retrive only name form the above database using angularfire new api.
ref=firebase.database().ref();
$scope.user=$firebaseArray(ref.child('users'));
in html
{{user.name}}
You could try
var id= 'LnsdgmDFX6WJi13B32abj5ah60O2';
var ref = firebase.database().ref('/users/').child(id);
$scope.user= $firebaseArray(ref);
and in your HTML
<li ng-repeat="user in user">
{{user.name}}
</li>

Querying in Firebase by child of child

I have a structure of objects in Firebase looking like this:
-KBP27k4iOTT2m873xSE
categories
Geography: true
Oceania: true
correctanswer: "Yaren (de facto)"
languages: "English"
question: "Nauru"
questiontype: "Text"
wronganswer1: "Majuro"
wronganswer2: "Mata-Utu"
wronganswer3: "Suva"
I'm trying to find objects by categories, so for instance I want all objects which has the category set to "Oceania".
I'm using Swift and I can't really seem to grasp the concept of how to query the data.
My query right now looks like this:
ref.queryEqualToValue("", childKey: "categories").queryOrderedByChild("Oceania")
Where ref is the reference to Firebase in that specific path.
However whatever I've tried I keep getting ALL data returned instead of the objects with category Oceania only.
My data is structured like this: baseurl/questions/
As you can see in the object example one question can have multiple categories added, so from what I've understood it's best to have a reference to the categories inside your objects.
I could change my structure to baseurl/questions/oceania/uniqueids/, but then I would get multiple entries covering the same data, but with different uniqueid, because the question would be present under both the categories oceania and geography.
By using the structure baseurl/questions/oceania/ and baseurl/questions/geography I could also just add unique ids under oceania and geography that points to a specific unique id inside baseurl/questions/uniqueids instead, but that would mean I'd have to keep track of a lot of references. Making a relations table so to speak.
I wonder if that's the way to go or? Should I restructure my data? The app isn't in production yet, so it's possible to restructure the data completely with no bigger consequences, other than I'd have to rewrite my code, that pushes data to Firebase.
Let me know, if all of this doesn't make sense and sorry for the wall of text :-)
Adding some additional code to Tim's answer for future reference.
Just use a deep query. The parent object key is not what is queried so it's 'ignored'. It doesn't matter whether it's a key generated by autoId or a dinosaur name - the query is on the child objects and the parent (key) is returned in snapshot.key.
Based on your Firebase structure, this will retrieve each child nodes where Oceania is true, one at a time:
let questionsRef = Firebase(url:"https://baseurl/questions")
questionsRef.queryOrderedByChild("categories/Oceania").queryEqualToValue(true)
.observeEventType(.ChildAdded, withBlock: { snapshot in
print(snapshot)
})
Edit: A question came up about loading all of the values at once (.value) instead of one at at time (.childAdded)
let questionsRef = Firebase(url:"https://baseurl/questions")
questionsRef.queryOrderedByChild("categories/Oceania").queryEqualToValue(true)
.observeSingleEventOfType(.Value, withBlock: { snapshot in
print(snapshot)
})
Results in (my Firebase structure is a little different but you get the idea) uid_1 did not have Oceania = true so it was omitted from the query
results.
Snap (users) {
"uid_0" = {
categories = {
Oceania = 1;
};
email = "dude#thing.com";
"first_name" = Bill;
};
"uid_2" = {
categories = {
Oceania = 1;
};
"first_name" = Peter;
};
}
I think this should work:
ref.queryOrderedByChild("categories/Oceania").queryEqualToValue(true)

How to retrieve only part of a document back in a call

I need to retrieve only part of a document and call it via a helper so that I can render a subtemplate multiple times as the part I require to pull from the db is an array of object itself. I have the following as the fields. What I need to do with my helper is only retrieve the ordersDispatch array of one particular document which would be uniquely called by the tripNumber field.
I have tried several things but nothing has come close to only having an array of the objects in the orderDisptach field be returned in a fashion that it can be used by the helper to render my subtemplate for each object in the array.
{
tripNumber: companyRecord.lastTripNum + 1,
custID: $('input:hidden[name=orderCustomerId]').val(),
custContact: $('input:text[name=customerContact]').val(),
custEmail: $('input:text[name=customerEmail]').val(),
trailerSealNum: $('input:text[name=trailerSealNum]').val(),
orderBroker: $('input:text[name=orderBroker]').val(),
orderEquipment: $('input:text[name=orderEquipment]').val(),
orderLoadNum: $('input:text[name=orderLoadNum]').val(),
orderPlacedDate: $('input:text[name=orderPlacedDate]').val(),
orderPrivateNotes: $('textarea[name=orderPrivateNotes]').val(),
orderPublicNotes: $('textarea[name=orderPublicNotes]').val(),
orderCurrency: $("input[name=orderCurrency]:checked").val(),
orderCharges: $('input:text[name=orderCharges]').val(),
orderFUELCheck: $('input:checkbox[name=orderFUELCheck]').is(':checked'),
orderFUELPerc: $('input:text[name=orderFUELPerc]').val(),
orderFUELTotal: $('input:text[name=orderFUELTotal]').val(),
orderGSTCheck: $('input:checkbox[name=orderGSTCheck]').is(':checked'),
orderGSTPerc: $('input:text[name=orderGSTPerc]').val(),
orderGSTTotal: $('input:text[name=orderGSTTotal]').val(),
orderPSTCheck: $('input:checkbox[name=orderPSTCheck]').is(':checked'),
orderPSTPerc: $('input:text[name=orderPSTPerc]').val(),
orderPSTTotal: $('input:text[name=orderPSTTotal]').val(),
orderTAXCheck: $('input:checkbox[name=orderTAXCheck]').is(':checked'),
orderTAXPerc: $('input:text[name=orderTAXPerc]').val(),
orderTAXTotal: $('input:text[name=orderTAXTotal]').val(),
orderTotalCharges: $('input:text[name=orderTotalCharges]').val(),
ordeBlockInvoicing: $('input:checkbox[name=ordeBlockInvoicing]').is(':checked'),
orderExtraCharges: orderExtraCharges,
orderPickups: puLocations,
orderDeliveries: delLocations,
orderDispatch: dispatchLocations,
createdDate: new Date(),
createdUser: currentUser.username
Any help in building a helper that will accomplish this would be greatly appreciated as I am new to meteor and mongo.
The following helper should give you what you need:
Template.oneTrip.helpers({
orderDispatch: function(tn){
return Trips.findOne({ tripNumber: tn }).orderDispatch;
}
});
Trips.findOne({ tripNumber: tn }) gets you an individual document and .orderDispatch returns the value of the orderDispatch key which in your case will be an array.
html:
<template name="oneTrip">
{{#each orderDispatch this._id}} <!-- assuming you've already set the data context to an individual order -->
{{this}} <!-- now the data context is an element of the orderDispatch array -->
{{/each}}
</template>

Loop over the Mongodb objects to get the values in Meteorjs

I am first Time working With Meteorjs and MongoDB. I am working on a Q&A application. where I have a list of objects which i got using Meteor database call. I want to looper over the list and want to split one of its attribute to the length 50 and then want to send a list of these splitted objects to the database.what I have is this
Template.questions.questions = function () {
questions= Meteor.questions.find({topic_id: Session.get("currentTopicId")});
return questions
}
Every question object in the questions list has an attribute question_text. Using loop i want to split this attribute to length of fifty and then want to push that to an empty list and return that list . Like
questions_list=[]
for(i=0;i<questions.length;i++){
question=questions[i].question_text[0:50] // python syntex to get first 50 char of a string
questions_list.push(question
}
return questions_list
and My HTML is like
<tbody>
{{#each questions}}
<tr>
<td class="span2" style="overflow:hidden;width:50px">
{{question_text}}
</td>
</tr>
{{/each}}
</tbody>
suggest me guys how can i acieve this in meteorjs. my problem is when i try to loop over this questions list there are many attributes like Collection, Results, Queries. here i am unable to iterate this list of objects.
In the same way how can i get the error message thrown back by meteorjs
This will give you list of shortened texts of all questions matching a query:
var questions = Questions.find({...}).map(function(question) {
return question.text.substr(0,50);
});
You could use it directly in a helper:
Template.questions.questions = function () {
return Questions.find({...}).map(function(question) {
return question.text.substr(0,50);
});
};
By the way, Questions.find({...}) does not return a list of questions, but a cursor object that you can use to manipulate query data in an effective way (like that map method above). To get raw array, you need to use fetch on that cursor: Questions.find({...}).fetch().
If you're just displaying the data you could create a handlebars helper:
Template.questions.helpers({
first50: function(question) {
return question.text.substr(0,50);
}
});
Then add the helper:
Template.questions.questions = function() {
return Questions.find({...});
};
Then in your template you could do:
<tbody>
{{#each questions}}
<tr>
<td class="span2" style="overflow:hidden;width:50px">
{{first50 question_text}}
</td>
</tr>
{{/each}}
</tbody>

Grails Searchable Plugin for multiple domain classes and multiple search fields with a single submit button

I have multiple domain objects and having one to many, many to many relationships and search data comes from couple of tables and it is always same. I implemented Searchable plugin in my app and able to retrieve results when I have single search field like this:
<g:form url='[controller: "searchable", action: "searchContact"]' id="searchableForm" name="searchableForm" method="get">
<g:textField name="query" value="${params.query}" size="40"/>
<input type="submit" value="Search Contact" />
</g:form>.
But I have multiple text fields, check boxes and g:select boxes to get searchTerm. Based on any one of fields or multiple search selections I have to get search results. How to include all search fields in between and having a single submit button for all the params. Here is my search action code:
def searchContact = {
if (!params.query) {
return [:]
}
try {
String searchTerm = params.query
println searchTerm
return [searchResult: searchableService.search(searchTerm, params)]
} catch (SearchEngineQueryParseException ex) {
return [parseException: true]
}
}
Quick suggestions are appreciated.
You can pass all the terms in one String query separating each token/word by a space, so for example if you have two Domain classes one called Person and another one called Job and you search for "John" and "Engineer", your String query should be "John Engineer" and that should get you both domain objects.
Is that kind of what you are looking for?