Mongoose - embedded documents are saved as string - node.js

In my node app I have designation model with following Schema.
var DesignationSchema = new Schema({
_id : ObjectId,
designation : String
});
And this is embedded in users Schema.
var UserSchema = new Schema({
fname:String,
lname :String,
email :String,
password :String,
designations : [DesignationSchema]
});
User can select one / many designations from select list. Below is my jade implementation for creating select list;
select(name="designations")
- for(var i = 0; i < designations.length; i++) {
option(value="#{designations[i]}", name="designations[#{i}]") #{designation.designation}
- }
But these values are stored as string array instead of DesignationSchema array:
{
designations : ["{designation:'Some Value' , _id : __DESIGNATION__ID}", "{designation:'Some Value' , _id : __DESIGNATION__ID}"]
}
UPDATE
I am pushing designations in following way in expressjs :
var newUser = new User(user.info);
if(user.designations && user.designations.length){
for(var i =0; i < user.designations.length; i ++) {
newUser.designations.push(user.designations[i]);
//I have tried JSON.parse(user.designations[i]) but it raises error that says : 'Unexpected token d'
//user.designations[i] object is something like : {designation:'Some Content', _id : __DESIGNATION__ID}
//IMPORTANT : the __DESIGNATION__ID is not inside single (') or double (") quotes. And I think this is the reason why JSON.parse is raising the error.
}
}

You can ommit the _id from DesignationSchema as Mongoose will add that for you itself. Make sure you JSON.stringify the data you POST/PUT/etc so that you are left with something you can parse.
You may also need to specify the content-type as application/json when you send the data back. This should allow you to avoid JSON.parse in your endpoint.

Related

how to query mongoDb with array of boolean fields?

My mongoose model schema looks like -
{
email: { type: String},
Date: {type: Date},
isOnboarded: {type: Boolean},
isVip: {type: Boolean},
isAdult: {type: Boolean}
}
In my frontend I have 3 checkboxes for "isVip", "isOnboarded" and "isAdult" options. If they are checked I'm adding them to an array, which I'll pass to the server. Let's say if "isVip" and "isAdult" are checked, I will pass [isVip, isAdult] in post api to server. Now how can I write a query to get all the documents with the fields in array as true i.e in above example how can I retrieve all docs with {isVip: true, isAdult:true}
I'm having trouble because the array values keep changing, it can be only one field or 3 fields. I couldn't find a way to give condition inside mongoose query.
User.find(
{ [req.query.array]: true},
{ projection: { _id: 0 } }
)
User is my mongoose model.
I want something like this (documents with the value 'true' for the fields given in the array) and 'req.query.array' is the array with field names I passed from frontend.
You have to create your object in JS and pass then to mongo in this way:
var query = {}
if(isVip) query["isVip"] = true;
if(isOnboarded) query["isOnboarded"] = true;
if(isAdult) query["isAdult"] = true;
And then you can use the mongoose method you want, for example:
var found = await model.find(query)
And this will return the document that matches the elements.
Also, note that this is to create and object to be read by the query, so you can use this into an aggregation pipeline or whatever you vant
Check the output:
var query = {}
query["isVip"] = true;
query["isOnboarded"] = true;
query["isAdult"] = true;
console.log(query)
Is the same object that is used to do the query here
{
"isVip": true,
"isOnboarded": true,
"isAdult": true
}
Also, to know if your post contains "isVip", "isOnboarded" or "isAdult" is a javascript question, not a mongo one, but you can use something like this (I assume you pass a string array):
var apiArray = ["isVip","isAdult"]
var isVip = apiArray.includes("isVip")
var isAdult = apiArray.includes("isAdult")
var isOnboarded = apiArray.includes("isOnboarded")
console.log("isVip: "+isVip)
console.log("isAdult: "+isAdult)
console.log("isOnboarded: "+isOnboarded)

Inserting into array error in Mongoose

This is my MongoDB schema, Seems like push operator is not working
locationCoordinate : {
type : [Number],
index: '2d'
},
i am getting Post data from frontend in my Node.js server which is having Longitude and Latitude
var event = new Events({})
(Events is the name of Schema )
I want to push into this array,
so this seems not to be working
Error on this line
event.locationCoordinate.push(req.body.longitude);
event.locationCoordinate.push(req.body.latitude);
And then saving this by
event.save(function(err,result)){
}
The result may be something like
locationCoordinate[1,2]
var array = [];
array.push({"lng":req.body.longitude},{"lat":req.body.latitude}); // or
array.push(req.body.longitude,req.body.latitude); //just try mybe work
var Evnt = new Events()
Evnt.type = array;
Evnt.index = req.body.index;
Evnt.save(function(...){ ... });

Confirm collection exists using mongoose

New to MongoDB so I hope I get the terminology correct...
I have a database that includes a user collection. In node I would like to check that value of a field, however, first I need to ensure the field exists.
For example here is my user schema:
var mongoose = require('mongoose');
var userSchema = mongoose.Schema({
local: {
email : String,
password : String,
},
facebook : {
id : String,
token : String,
email : String,
name : String
}
}
Some users have both a local and facebook documents/fields? whereas others may have either.
I wish to confirm the is the current user document has an email value in both fields if both fields exist in the document. i.e.
User.local.email & User.facebook.email
If I try to access the email field directly and the field does not exist for that document I get:
TypeError: Cannot read property 'email' of undefined
Try this -
var localExists = User.local != null;
var facebookExists = User.facebook != null;
if(localExists && facebookExists){
// both exist so check if both have email
var bothHaveEmail = User.local.email != null && User.facebook.email != null;
}
else if(localExists){
// only local exists
}
else if (facebookExists){
// only facebook exists
}
else{
// nothing exists
}
You could try
const localEmail = user.local && user.local.email;
const fbEmail = user.facebook && user.facebook.email;
If either is set to undefined that means that that email field doesn't exist

how to use in operator in dynamo db

I have a user table with a field username. I need to write something equivalent to this in dynamo db: Select * from user where username in('a','b','c');
Adding more from code prosepective i have usernames in an array say var arr=['a','b','c'];
I so far tried this which is giving me zero result
this.dynamo.client.scanAsync({
TableName: this.dynamo.table('users'),
FilterExpression: 'username IN (:list)',
ExpressionAttributeValues: {
':list': arr.toString()
}
}).then((response) => {
console.log(response);
return {
userFriends: result.Item.friends
};
});
When I pass one element in array it give me result searching passed single element in user table but its not working with more than one element in array.
The individual users should be given as comma separated String variables. JavaScript array is equivalent to List in AWS DynamoDB data type. The DynamoDB can't compare the String data type in database with List attribute (i.e. Array in JavaScript).
var params = {
TableName : "Users",
FilterExpression : "username IN (:user1, :user2)",
ExpressionAttributeValues : {
":user1" : "john",
":user2" : "mike"
}
};
Construct the object from array for FilterExpression:-
Please refer the below code for forming the object dynamically based on Array value.
var titleValues = ["The Big New Movie 2012", "The Big New Movie"];
var titleObject = {};
var index = 0;
titleValues.forEach(function(value) {
index++;
var titleKey = ":titlevalue"+index;
titleObject[titleKey.toString()] = value;
});
var params = {
TableName : "Movies",
FilterExpression : "title IN ("+Object.keys(titleObject).toString()+ ")",
ExpressionAttributeValues : titleObject
};
Note:-
I don't think IN clause with 1000s of usernames is a good idea in terms of performance.

Dynamic URL with mongo method

Regarding these post : Mongoose prototype : how to insert an url dynamically?
I'm looking to do pretty much the same (URI dynamically insert).
The solution provided is good but I do not understand some things...
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var PicturesSchema = new Schema({
album : { type : String, required : true, trim : true },
pictures : { type : Array, required : false, trim : true }
});
PicturesSchema.virtual('pictureUrls').get(function() {
return this.pictures.map(function(picture) {
return 'https://s3.amazonaws.com/xxxxx/'+ picture;
});
});
var Pictures = mongoose.model('Pictures', PicturesSchema);
// Demo:
var pictures = new Pictures({
album : 'album1',
pictures : [
'1434536659272.jpg',
'1434536656464.jpg',
'1434535467767.jpg'
]
});
console.log( pictures.getPics() );
The given solution injects a "virtual field" in addition to retaining the "pictures" field with the name of the images (without URL).
How to retain only the field "PicturesURL" containing the full URL of the image without displaying a redundancy with the "Pictures" field?
How to retrieve and display the JSON format query results as it knowing that data.ToJson returns an error: has no method 'toJson'?
Pictures.find().exec(function(err, data){
if(err){
console.log(err);
}
console.log('%j', data.toJSON({ virtuals : true }) );
});
A strategy to store only the picture url without the picture would be to create a Mongoose middleware on save.
You could then populate the picture field with the name of the picture, and the full url will be the one stored in the database and later retrieved.
For example:
PictureSchema.pre('save', function (next){
if (this.isModified(pictureUrls){
this.pictureUrls = this.pictureUrls.map(function(picture){
return 'https://s3.amazonaws.com/xxxxx/'+ picture;
})
}
});
With this solution, every time you modify the pictures array, it will go over every element of the array and add the s3 path.
Since it won't be a virtual, it will be easier for you to use the model with event using toObject or toJson.

Resources