Finding nested array data with elemMatch in MongoDB/Meteor - javascript

collection structure as such:
{"_id" : "abc",
"potentialUsers" : [{"userID" : "def"},
{"userID" : "ghi"}]
},
{"_id" : "123",
"potentialUsers" : [{"userID" : "456"},
{"userID" : "789"}]
},
I want to query if user abc has the user def in their potential users array. My current query (client) is
getPendingLiftRequests: function() {
return collection.find({}, {potentialUsers: {$elemMatch: {userID: Meteor.user().services.facebook.id}}});
}
On the server I publish all of that collection to the user, and then just selectively show it based on the view of the client. However, when I try to use an elemMatch on the array, it just shows all of the records, when it should only show 1.

You don't need $elemMatch here. This should work:
var fId = Meteor.user().services.facebook.id;
return collection.find({'potentialUsers.userID': fid});

Have look at the documentation for minimongo in Meteor:
http://docs.meteor.com/#/full/find
You have to use the fields option to get the desired result.
getPendingLiftRequests: function() {
return collection.find({}, { fields: { potentialUsers: {$elemMatch: {userID: Meteor.user().services.facebook.id}}}});
}

Related

Node js, Mongoose query to match id with values stored as comma separated string

I am new to the Mongoose and NodeJS world.
I have product document where I am storing category ids as shown below.
"reviewscount" : "2",
"overallrating" : "4.5",
"urlkey" : "strive-shoulder-pack",
"productid" : "2",
"categoryid" : "3,7,4",
Now wanted to fetch all the products belongs to one category based on category Id.
I tried below code, but getting empty result
Product.find({ "categoryid" : { "$in" : [ categoryId ] } }, function (err, products) {
console.log(products);
}
Am I doing it wrong way?
This would check whether the whole categoryid is equal to something in the in-array.
You basically got two options, the first (preferred) is to store your categoryid(s) as an array instead of csv and use a simple query as seens in this answer.
The second option is to manually (mongoose docs) parse the categoryid against your Id, but that wont scale very well (besides other problems).
Product.find({$where : 'this.categoryid.indexOf("' + categoryId + '") != -1'});
Product.find({ "categoryid" : { "$in" : [ categoryId ] } }, function (err, products) {
console.log(products);
}
for this type query you need to convert in your schema.
"reviewscount" : "2",
"overallrating" : "4.5",
"urlkey" : "strive-shoulder-pack",
"productid" : "2",
"categoryid" : [3,7,4] // convert in your schema make categoryid:[Number]
to insert in categoryid use $addToSet with $each if you want unique value in array.

Get unique id of specific element in Firebase

I have my Firebase database structured like this:
{
"userProfile" : {
"X0u2SEFfYEeVmdw4TXl58ou2eYy1" : {
"email" : "jane#yahoo.com",
"name" : "Jane"
},
"cliv7hQ4FsWKTtYksPDXcdDafdi2" : {
"email" : "doe#gmail.com",
"name" : "John Doe",
}
}
}
I'm trying to get the unique id of the element that matches query criteria, for example the key of the element with email equal to doe#gmail.com.
I'm doing this by using:
firebase.database().ref('/userProfile').orderByChild('email').equalTo(email).once( 'value', data => {
let user = data.val();
});
This returns me the entire object with that email, but I only want its unique id ("cliv7hQ4FsWKTtYksPDXcdDafdi2" in this case). What's the best way to achieve this?
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
So:
var query = firebase.database().ref('/userProfile').orderByChild('email').equalTo(email);
query.once( 'value', data => {
data.forEach(userSnapshot => {
let user = userSnapshot.val();
let key = userSnapshot.key;
});
});

mongoDB - $push _id to specific users

I want to push an _id to specific users, but unfortunately it does not work as expected.
Here is my code:
var chatId = Chat.insert(privateMessage);
Users.update({_id: {$in: participants}}, {$push: {chat: chatId}});
I want to push the chatId to all users within the participants array.
The participants array looks like this: [ '3JsJP8MJZXRdACJqs', 'En2mTYgRj3BkHc6AW', 'p3kgiZbjYpvvYAWYs' ]. After checking the result, I noticed that only the user with the _id: 3JsJP8MJZXRdACJqs had the chatId in the document.
Any help would be greatly appreciated.
By default, the update() method updates a single document. To update multiple documents, use the multi option in the update() method.
as:
Users.update({
_id : {
$in : participants
}
}, {
$push : {
chat : chatId
}
},
{multi : true}
);
Refer: http://docs.mongodb.org/manual/tutorial/modify-documents/#update-multiple-documents

execMatch only returning first result

I am trying to find a particular record (with an id of 1) and then to return only its history field. This history field is an array of objects with a timestamp property. When I return this history field, I want it to contain only objects with timestamp properties greater than 0.
Sample collection
[{
"_id" : 1,
"history" : [
{
"content" : "hello",
"timestamp" : 1394639953878,
"_id" : ObjectId("53208451767743b748ddbd7d")
},
{
"content" : "world",
"timestamp" : 1394639953879,
"_id" : ObjectId("33208451767743b748ddbd7e")
}
]
}]
Thus, according to Mongo and Mongoose documentation, I do something like:
model.find({_id: 1})
.select({ history: { $elemMatch: { timestamp: { $gt: 0 } } } });
The issue: I understand that there will only be one result (since I select the id 1) but I am using $elemMatch to populate its history field with all objects that have a timestamp greater than 0. The issue is that only one object is ever in history.
The $elemMatch projection returns only the first matching element satisfying the condition. Checkout the documentation.
Using aggregate would be the right approach to achieve what you want I think. Please see below:
db.bar.aggregate([
{$match:{_id:1}},
{$unwind:"$history"},
{$match:{"history.timestamp":{$gt:0}}},
{$group:{_id:"$_id", history:{$push:"$history"}}}
])

iterating over collection in backbone.js

var User = Backbone.Model.extend({
defaults : {
"students" : [
{
name : "abc",
grade: "A",
school: "xyz"
}],
"interest":
{
music : "yes"
}
}
});
var UserList = Backbone.Collection.extend({
model : User,
});
var obj = new UserList({"students" : [{name:"Rax", grade: "B", school : "javiers"}, {name:"John", grade: "C", school : "loreto"}], "interest" : {music: "yes"}});
for(var i = 0; i < obj.students.length; i++) {
console.log(obj.students.at(i).get("name"));
console.log(obj.students.at(i).get("grade"));
console.log(obj.students.at(i).get("school"));
}
//i want to iterate over each students detail(name, grade and school) ..but this is giving me error " obj.students is undefined " ..why this error is coming?
First of all, there are several syntax errors, so look into console and fix these. Also, something is conceptually wrong with the object you pass to collection.
Collection is a "user list", the model is one user. So, perhaps, you should change the defaults data description. It doesn't make sense to make students an array for a user.
Also, when you create an instance of Collection, you then create a model by using create method, and not by just passing in the hash. You could instatinate the Model that way, but not the Collection.
So when you want to create a user, you pass only one "student" in, perhaps something like this (you also have to put "url" key in your Collection, otherwise it won't work):
var User = Backbone.Model.extend({
defaults : {
"students" : [{
name : "abc",
grade: "A",
school: "xyz"
}],
"interest":{
music : "yes"
}
}
});
var UserList = Backbone.Collection.extend({
model : User,
// `url` is required, otherwise Backbone will throw an error
url : '/something'
});
var userList = new UserList();
var bob = userList.create({
students : [ {
name:'bob',
grade : 'a',
school : '123'
} ],
interest : { music : 'no' }
});
console.log( bob.get('students')[0].grade );
http://jsbin.com/elusey – here, hit "edit" and take a look at the code and in the console. You should see "a" as an output.
You could actually simplify the model to this (as I told, the data structure described above doesn't really make sense for a single user):
var User = Backbone.Model.extend({
defaults : {
name : "abc",
grade : "A",
school : "xyz"
interests : ["music"]
}
});
UPD. Actually, you don't have to use create collection method in order to add models to your collection. When you create an instance of your collection you can pass in an array of models, something like this (note the difference, in your code you pass an object to a collection, but you actually need to pass an array, even if with one object in it):
var userList = new UserList([{
name:'bob',
grade : 'A',
school : '123',
interests : [ "music" ]
},{
name:'george',
grade : 'B',
school : '321',
interests : [ "drugs" ]
}]);
You can find the working example that is using this way of adding models (don't forget to look into console) here: http://jsbin.com/elusey/2/edit
Are you sure a user 'has many' students? That doesn't make much sense. However, if that is the case, you should add a definition for a student model and collection of students. Than, your user model should contain a student collection, and some logic in the set() method to transform an array of students to a students collection. If you want to handle collections/models nested under a model more gracefully, take a look at Backbone-relational.

Categories

Resources