How to do a query using dot( . ) through Mongoose in Node.js and How to add an empty array - arrays

I have the following schema:
var userSchema = new Schema({
userID: Number,
userName: String,
userEmail: String,
teams:Array,
socialMedias:
{
fbUID: String,
googleUID: String,
twitter: String }
});
First, How can I add an empty array? Is it right the way I am doing in the following?
teams:{},
Second, I am trying to do a query using Mongoose in my Node.js but I am getting an error in the dot ('.'):
This is my document I am saving:
var user = new users({
userID: id, //give the id of the next user in Dbase
userName: userName,
userEmail: 'userEmail',
teams:{},
socialMedias: [{socialMediaType: socialMediaID}]
});
where userName, socialMediaType and socialMediaID are parameters of a function.
So, after I add this doc, I am trying to do the following query:
function searchUser(socialMediaID, socialMediaType){
var user
users.findOne({socialMedias.socialMediaType: socialMediaID}, function(err, userFound){
if(err) return handleError(err);
user = userFound;
});
//what does MongoDb return if it does not find the document?
return user;
}
but I am getting an error in this :
socialMedias.socialMediaType
So, how can I do this query?
I tried to find in Mongoose Documentation but I did not find.
Thank you for your understanding.

There's a number of issues here that you are likely running into.
First, teams is an array property, but you're assigning an object to it. You need to do something like this:
var user = new users({
userID: id, //give the id of the next user in Dbase
userName: userName,
userEmail: 'userEmail',
teams:[],
socialMedias: [{socialMediaType: socialMediaID}]
});
Second, if socialMediaType is passed in as a function param, you can't use it like you're doing. You need to do something like this:
var socialMedias = {};
socialMedias[socialMediaType] = socialMediaID;
var user = new users({
userID: id, //give the id of the next user in Dbase
userName: userName,
userEmail: 'userEmail',
teams:[],
socialMedias: [socialMedias]
});
Third your findOne is not going to work as is. From what I can gather of your intention here, you need something like this:
function searchUser(socialMediaID, socialMediaType){
var user
var query = {};
query["socialMedias."+socialMediaType] = socialMediaID;
users.findOne(query, function(err, userFound){
if(err) return handleError(err);
user = userFound;
});
//what does MongoDb return if it does not find the document?
return user;
}
But fourth, even that won't work because you are synchronously returning user from a method that performs and asynchronous operation. There are various ways to solve that, but you can start by reading up about promises, or passing a callback function into searchUser.

Related

Update boolean with Mongoose

I have created an app where i can create a to do list. And i have a status that is false when created. The status i supposed to represent if the object done or not.
My mongoose schema look like this in server.js:
// Create mongoose schema
var issueSchema = mongoose.Schema ({
issue: String,
date: String,
status: Boolean,
});
// Create mongoose model
Issue = mongoose.model('Issue', issueSchema);
When i press my button in on my index.html im using angular to send the id trough to the server.js file.
// API PUT ========================
app.put('/issueList/:id', function(req, res){
var id = req.params.id;
Issue.findById(id, function(err, Issue) {
console.log("Object with ID: " + id); // Correct ID
// I need code here
});
});
I need help updating the boolean value to true if false or false if true. Or should i skip the boolean value and use something else?
You can find the issue by id and then save it back to MongoDB after making the changes in success callback.
Issue.findById(id, function(err, issue) {
issue.status = !issue.status;
issue.save(function (err) {
if(err) {
console.error('ERROR!');
}
});
});
I am not sure about the possibility of toggling boolean field atomically as of now in MongoDB.
First, i dont think you should use same variable name outside and inside the function. In this case Issue is same, change it to issue.
And you can try this to update.
Issue.findById(id, function(err, issue) {
console.log("Object with ID: " + id); // Correct ID
issue.status = !issue.status;
issue.save(function(err,result){...});
});
});

Posting Schema.Types.ObjectId arrays to MongoDB

How can I post an array of Schema.Types.ObjectId (s) to MongoDB? I'm trying to create User Groups, which is a group of the 'User' Model e.g.
var UserGroup = new Schema({
users: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
});
New UserGroup Function
module.exports.create = function(request, response) {
var group = new UserGroup({
users = request.body.users
});
group.save(function(error) {
if(error) { throw error; } else { response.send('Group Created Successfully.');
});
};
I'm currently using Postman to test the functionality, how exactly should the data be posted?
As a Javascript array i.e ['A_USER_ID', 'A_USER_ID'] ?
Thanks!
#Answer
I was using the older syntax of the select() function, and therefore was passing invalid parameters to the $push function. When sending the request, I simply pass the ObjectIds as id,id,id and once they get to the server, simply put it into an array using var my_array = request.body.users.split(','); and then push it to the database using the following:
$push: { users: { $each: my_array } }
I hope this was helpful, the documentation isn't particularly clear on this matter.

Meteor.users subscribe only return current user

I'm trying to get a user by the username, when I use Meteor.users.findOne, it always return the current user. And if I user Meteor.users.find, it returns all current user document, and the profile.firstName and profile.lastName of the right matched username.
Meteor.publish('userByUsername', function(username) {
return Meteor.users.findOne({
username: username
}, {
fields: {
'profile.firstName': 1,
'profile.lastName': 1,
}
});
});
How can I get only the user that match with the username?
I think what you want is not publish, but a method access to particular username. Publish/Subscribe is great for datasets that often change - say posts on stackoverflow, facebook feed, news articles, etc.
You are looking to get first/last name of a particular user, this does not really change. So what you actually want is to create a server method that returns the first/last name of the user. And you can call this method from the client to access this data.
if (Meteor.isClient) {
//get username var
Meteor.call('findUser', username, function(err, res) {
console.log(res.profile.firstName + " " + res.profile.lastName);
});
}
if (Meteor.isServer) {
Meteor.methods({
findUser: function(username) {
return Meteor.users.findOne({
username: username
}, {
fields: {
'profile.firstName': 1,
'profile.lastName': 1
}
});
}
});
}
Notice that the client Meteor.call has a callback method. DB queries on Meteor server is asynchronous & non-blocking, so you need to access the result via a javascript callback function.
findOne finds and returns the first document that matches the selector. Publish method needs to return a cursor, you need to use find, instead of findOne:
Meteor.publish('userByUsername', function(username) {
return Meteor.users.find({
username: username
}, {
fields: {
'profile.firstName': 1,
'profile.lastName': 1,
}
});
});
Then you can call subscribe on the client:
Meteor.subscribe('userByUsername', 'bob');
And call Meteor.users.findOne({ username: 'bob' }); in your helper for example.

NodeJS create json object from array

I'm working with some arrays in node and I want to send if as one JSON object to the front-end. I use express to do this. I have a model called User where I find users based on their email. That email is provided in an array. I do get the user object but I can't create one JSON object out of them!
I have tried some middleware but that didn't give me any result! https://www.npmjs.com/package/node.extend
var users = {};
for (var i = 0; i <emails.length; i++) {
User.findOne({
'email': project.students[i]
}, function (err, user) {
if (err) {
res.send(err);
}
// Fill the users object with each user found based on the email
});
}
console.log(users); // Should be one JSONObject
Thanks for the help!
You should be able to do this in a single query. It looks like you're using mongoose, so try something like this:
User.find({ email: { $in: emails } }, function(err, results) {
if (err) return res.send(err);
res.send(results);
});
It's also worth noting that javascript is single threaded. This means that a lot of operations happen asynchronously, meaning you have to wait for the operation to get done before you can move on. Your console logging statement above doesn't wait for the database operation to complete. You have to wait for the callback function to execute.
UPDATE: Also just noticed that you are looping over emails but then using project.students[i] within each iteration. I can't see the rest of your code, but this is just buggy code. You should be either looping over project.students or using emails[i] within each iteration.
UPDATE 2: It appears that you are wanting to send more than just an array of user with the response. So the first goal is to use a single query using the $in operator (see example above - you should be able to pass a list of emails to mongoose). Anything mongo-related, you always want to reduce the amount of queries to the database if you care at all about performance. The second task is to reformat your users and other data accordingly:
var finalResponse = { token: "12341234", users: null };
User.find({ email: { $in: emails } }, function(err, results) {
if (err) return res.send(err);
if (!results.length) return res.send(finalResponse);
// OPTION 1: Array of users (recommended)
finalResponse.users = results;
// OPTION 2: users object, keyed by the users email
finalResponse.users = {};
results.forEach(function(user) {
finalResponse.users[user.email] = user;
});
// FINALLY, send the response
resp.send(finalResponse);
});

AngularFire: Getting the ID of Users Data from email in SimpleLogin

I'm trying to implement some simple using registration using Firebase through AngularFire and Angular.js. I'm using the SimpleLogin tool to manage the users. I can create users just fine.
var firebaseRef = new Firebase(FIREBASE_URL);
var simpleLogin = $firebaseSimpleLogin(firebaseRef);
var firebaseUsersRef = new Firebase(FIREBASE_URL + 'users');
var firebaseUsers = $firebase(firebaseUsersRef);
var myObject = {
register: function(user) {
var myDate = new Date().getTime();
return simpleLogin.$createUser(
user.email, user.password)
.then(function(regUser) {
var userInfo = {
date: myDate,
md5: regUser.md5_hash,
firstname: user.firstname,
lastname: user.lastname,
email: user.email
}
firebaseUsers.$push(userInfo).then(function(ref) {
userInfo.uid = ref.name();
$rootScope.currentUser = userInfo;
});
}); //push user
}, //register
Works like a charm. In order to get at this information when the user logs in, I've tried implementing an event handler on the $rootscope. I would like it to search through the uid that I stored and then get me record with the right user information.
$rootScope.$on('$firebaseSimpleLogin:login', function (e, authUser) {
var query = $firebase(firebaseRef.startAt(authUser.uid).endAt(authUser.uid));
console.log(query);
$location.path('/meetings');
});
In order to use startAt and endAt, do I have to establish $priority. When I try, I get an error stating that I can't have any special characters. So that never works. I don't really care about how this data stored, I just want to get the index of the data so that I can retrieve the right user.
By using $push you tell Firebase to generate a key for you.
This is great for collections where you normally access all children at the same time. But that is not the case for your user info: you want to access the info for the current user.
So instead of using $push to add your user's info, I would use the uid of the user.
In the regular Firebase JavaScript API this can be accomplish with:
firebaseUsersRef.child(reguser.uid).set(userInfo);
The equivalent in AngularFire probably uses $set, but I don't think you have any need for that in your $createUser callback.
Update
It looks like you're trying to add your info to the existing user node that Firebase creates for you. This is the example from that from the Firebase documentation on storing user data:
myRef.child('users').child(user.uid).set({
displayName: user.displayName,
provider: user.provider,
provider_id: user.id
});
You can see that they do access the user's node using child(user.uid) similar to what I proposed.
Lessons
Two relatively small mistakes here as far as I can see:
when you use push/$push, you let Firebase generate the node name for you. In cases where there already is a globally unique ID (such as the uid of a user), you're often better off using that as the node name.
If you know the name of the node you want to retrieve, you don't need a query. You can simply access the node as ref.child(user.uid).
Thanks to Frank, I was able to figure out the right way to do this. In order to make my own users object searchable, I can use the uid from the simpleLogin object. So my register function works like this:
var firebaseRef = new Firebase(FIREBASE_URL);
var simpleLogin = $firebaseSimpleLogin(firebaseRef);
var myObject = {
register: function(user) {
var myDate = new Date().getTime();
return simpleLogin.$createUser(user.email, user.password)
.then(function(regUser) {
var userInfo = {
date: myDate,
md5: regUser.md5_hash,
firstname: user.firstname,
lastname: user.lastname,
email: user.email
}
firebaseUsers.$set(regUser.uid, userInfo);
}); //add user
}, //register
} //my Object
Using set instead of push, I can store the uid from the registered user into the object and then pass along what I want to add as the second parameter. My database will now have the users organized by uid, which can be accessed via a url.
Then, when users log in, Firebase will throw up a login event along with the authenticated user, which I can catch and use to add the current user to the $rootScope that's accessible throughout my application.
$rootScope.$on('$firebaseSimpleLogin:login', function (e, authUser) {
var ref = new Firebase(FIREBASE_URL + '/users/' + authUser.uid);
var user = $firebase(ref).$asObject();
user.$loaded().then(function() {
$rootScope.currentUser = user;
});
$location.path('/meetings');
});
Thanks for pointing me in the right direction Frank.

Resources