Can one field have many value? - node.js

For example, I have a Scheme like this:
var User_schema = new Schema({
name: string,
image:{
avartar_image: String,
thumbnai_image: String,
story_image: String
}
});
Is it possible to create one field have many value like that in nodejs and mongoose? And one more, how can I store the image into mongodb and can push back to client using mongoose?, I store image on mongodb with Buffer, like this :
var Imgschema = new Schema({
img: Buffer;
});
And if send it to the user when user request a link on server, I do like this:
app.get('/', function (req, res, next) {
Imgschema.findById('5cdnjwjadhad_ad14', function (err, object) {
res.contentType('image/png');
res.send(object.image, {imageToClient: object.image});
});
});
It will send the image to the user with full screen, but I want the image display inside the tag with view engine, something like this:
<img src="{{imageToClient}}">
Any one help please, Thanks.

Of course you can. There are two ways to store a nested object with mongoose. You can use a subdocument, or just nest the object like you did. The difference between two methods is only a middleware and autogenerated _id field. Here is a good answer: Mongoose subdocuments vs nested schema
Storing images as a buffer in a document is not a good idea, but if you want, you can use base64 decoding to show image in browser.
<img src="{{ 'data:image/png;base64,' + imageBuffer.toString('base64') }}" />

Related

Passing Route Parameter to Mongoose Query Express

Basically I'm trying to find a way in which to find a way to plug req.params.name into a find() query.
I have tried:
Trying to pass through my req.params variable in my find() object parameter Card.find({cardName: req.params.name}, callback) and any other possible variance of that.
I've tried a static method for findByName in which I just did Card.findByName(req.params.name, callback);
When I do console.lo(req.params.name) it returns the name of the card; however, when I got to show.ejs I do console.log(cardstatsok.cardName) it comes back undefined.
I've searched here on Stack Overflow, I've checked my Udemy message board, and I've tried finding any tutorial on passing route parameters to a find query, and alas, nothing.
Here's my code:
My schema and model:
var cardSchema = new mongoose.Schema({
cardName: String,
id: Number,
cardSet: String,
image: String,
ability: String
});
var Card = mongoose.model("Card", cardSchema);
My route for my single card page:
app.get("/cards/:name", function(req, res) {
Card.find({"cardName":req.params.name}, function(err, cardInfo){
if(err){
res.redirect("/cards");
console.log(err);
} else {
res.render("show", {cardstatsok: cardInfo});
}
});
});
When I do console.log(cardInfo) it returns many objects since I used "Forest" and the copy of the Magic: The Gathering card Forest has been printed many times. Here's one, though:
{ _id: 5a85bb554c8fff0c04f15b8e,
cardName: 'Forest',
id: 243461,
cardSet: 'Duel Decks: Knights vs. Dragons',
image: 'http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=243461&type=card',
__v: 0 }
find() returns an array which means cardstatsok is an array.
So console.log(cardstatsok.cardName) won't work. Use console.log(cardstatsok[0].cardName) instead for the first card or console.log(cardstatsok) for everything. If you want to print all the card names you have to loop over the array.
To find only one card you can use findOne() instead.

Why is my buffer automatically converted to a nested array

My buffer format is being changed while trying to retrieve it from the MongoDB database, I'm not sure which step of the process is changing it.
I defined the mongoose schema as a buffer:
var mealSchema = mongoose.Schema({
picture: Buffer,
It looks like a what I expected in the database, a normal buffer:
{ "_id" : ObjectId("5691d1f73131c0db2b056447"), "picture" : BinData(0,"/9j/4TcORXhpZgAASUkqAKw2AA....
This is the code I used to send the buffer back to the client:
findAllMeals({})
.then(function(meals) {
res.send(200, meals);
This is how the client is receiving it back :
Object {type: "Buffer", data: Array[86690]}
[0 … 9999]
[10000 … 19999]
[20000 … 29999]
[30000 … 39999]
[40000 … 49999]
[50000 … 59999]
[60000 … 69999]
[70000 … 79999]
[80000 … 86689]
length: 86690
It became an array of arrays, it's being stored as a buffer, and being send back an nested arrays.
I also tried converting it to base64 in angular to see if it would convert it, it didn't.
I changed the storage data type in the schema to string, it didn't change anything, There's isn't much else I can think of changing to troubleshoot.
It's not an array of arrays, it's a Buffer object with a big data array (console.log splits it to ease the logging). One solution would be to exclude the pictures and then have a different route to fetch the picture for a specific meal (because express can deal with buffers automatically):
// first route, exclude pictures
app.get('/meals', function(req, res, next) {
findAllMeals({}, {
picture: 0
})
.then(function(meals) {
res.send(200, meals);
});
});
// second route to fetch the picture of a meal
app.get('/meal_picture/:mealId', function(req, res, next) {
findOneMeal({
_id: req.params.mealId
}).then(function(meal) {
res.status(200).send(meal.picture);
});
});
Then, in your html, you can simply write:
<img src='/meal_picture/5691d1f73131c0db2b056447'></img>
Side note, res.send(200, meals) is deprecated, use res.status(200).send(meals).
so I got it to work by changing the data type in the schema to
picture: {data: Buffer, contentType: String},
then in the client side I converted the base
<img ng-src="data:image/JPEG;base64,{{meal.picture}}"/>
and I managed to keep everything in the same REST request !

Data modeling in mongoDB - Social-media app

I'm trying to build some sort of a social media app using node.js and mongoDB.
I have a mongoose schema for 'User', and when i render some user page on the app, it needs to also show all of his posts/images/list of friends and etc...
right now i have a mongoose schema for 'UserPost' and also for 'Image', and when i save an image for example, it has a field which keeps the username of the user who uploaded it, so when i render the user page it finds all of his images.
It is the first time i'm dealing with db's so i heard that i might have to use a reference data instead of embedded data.
can someone explain to how should i organize the data model for my app?
It's very handful to use mongoose population for handling db references
Define your schemas like these:
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var userSchema = Schema({
name : String,
posts : [{ type: Schema.Types.ObjectId, ref: 'Post' }]
});
var postSchema = Schema({
title : String,
images : [{ url: String, filename: String }]
});
var User = mongoose.model('User', userSchema);
var Post = mongoose.model('Post', postSchema);
According to mongoose population docs, you can get all your data:
User.findOne().populate('posts').exec(function(error, user) {
console.log(user.posts) // there are populated posts objects inside array
})
Not sure, is it a good idea to use separated collection for image uploads, it's simpier to embed it inside Post (or User), but you may always add { type: Schema.Types.ObjectId, ref: 'Image' } for images
MongoDB is a NoSql DBMS. It means, you schould not create references between data fields, because the performance coming from NoSql will be killed: https://en.wikipedia.org/wiki/NoSQL
But, if you are really thinking you need references, checkout this: http://docs.mongodb.org/master/reference/database-references/
You can reference to a data document in the mongoDB by the _id ("Page"=>"createdBy" = "User"=>"_id" for example).
It depends of what kind of data you want to embed. MongoDB has object size limits according to the storage engine you use. Thus you should predict or estimate the the size of the object you want to embed.
See more about limits here: http://docs.mongodb.org/master/reference/limits/
See more about references here: http://docs.mongodb.org/master/reference/database-references/

Mongoose key/val set on instance not show in JSON or Console.. why?

I have some information on my mongoose models which is transient. For performance reasons I dont wish to store it against the model.. But I do want to be able to provide this information to clients that connect to my server and ask for it.
Here's a simple example:
var mongoose = require('mongoose'),
db = require('./dbconn').dbconn;
var PersonSchema = new mongoose.Schema({
name : String,
age : Number,
});
var Person = db.model('Person', PersonSchema);
var fred = new Person({ name: 'fred', age: 100 });
The Person schema has two attributes that I want to store (name, and age).. This works.. and we see in the console:
console.log(fred);
{ name: 'fred', age: 100, _id: 509edc9d8aafee8672000001 }
I do however have one attribute ("status") that rapidly changes and I dont want to store this in the database.. but I do want to track it dynamically and provide it to clients so I add it onto the instance as a key/val pair.
fred.status = "alive";
If we look at fred in the console again after adding the "alive" key/val pair we again see fred, but his status isnt shown:
{ name: 'fred', age: 100, _id: 509edc9d8aafee8672000001 }
Yet the key/val pair is definitely there.. we see that:
console.log(fred.status);
renders:
alive
The same is true of the JSON representation of the object that I'm sending to clients.. the "status" isnt included..
I dont understand why.. can anyone help?
Or, alternatively, is there a better approach for adding attributes to mongoose schemas that aren't persisted to the database?
Adding the following to your schema should do what you want:
PersonSchema.virtual('status').get(function() {
return this._status;
});
PersonSchema.virtual('status').set(function(status) {
return this._status = status;
});
PersonSchema.set('toObject', {
getters: true
});
This adds the virtual attribute status - it will not be persisted because it's a virtual. The last part is needed to make your console log output correctly. From the docs:
To have all virtuals show up in your console.log output, set the
toObject option to { getters: true }
Also note that you need to use an internal property name other than status (here I used _status). If you use the same name, you will enter an infinite recursive loop when executing a get.
Simply call .toObject() on the data object.
For you code will be like:
fred.toObject()
This has been very helpful. I had to struggle with this myself.
In my case, I was getting a document from mongoose. When I added a new key, the key was not visible to the object if I console.log it. When I searched for the key (console.log(data.status), I could see it in the log but not visible if I logged the entire object.
After reading this response thread, it worked.
For example, I got an object like this one from my MongoDB call:
`Model.find({}).then(result=> {
//console.log(result);// [{ name:'John Doe', email:'john#john.com'}];
//To add another key to the result, I had to change that result like this:
var d = result[0];
var newData = d.toJSON();
newData["status"] = "alive";
console.log(newData);// { name:'John Doe', email:'john#john.com', status:'alive'};
}).catch(err=>console.log(err))`
Hope this helps someone else.
HappyCoding

finding objectIds between two given values in mongodb and nodejs

I am creaing schemas similar to newsposts with an option for users to like and dislike them.
Here are the schemas for same
Client= new mongoose.Schema({
ip:String
})
Rates = new mongoose.Schema({
client:ObjectId,
newsid:ObjectId,
rate:Number
})
News = new mongoose.Schema({
title: String,
body: String,
likes:{type:Number,default:0},
dislikes:{type:Number,default:0},
created:Date,
// tag:String,
client:ObjectId,
tag:String,
ff:{type:Number,default:20}
});
var newsm=mongoose.model('News', News);
var clientm=mongoose.model('Client', Client);
var ratesm=mongoose.model('Rates', Rates);
In order to retreive the ratingsgiven by a particular user having given a set of newsposts, I tried,
newsm.find({tag:tag[req.params.tag_id]},[],{ sort:{created:-1},limit: buffer+1 },function(err,news){
ratesm.find({
client:client._id,
newsid:{$lte:news[0]._id,$gte:news.slice(-1)[0]._id}
},
function(err,ratings){
})
})
This query returns empty list no matter what. I doubt whether $gte and $lte be used to compare objectIds. Am I right? How can I which posts a user has liked/disliked in a given set of newsposts?
Yes, ObjectIds can be queried with range queries like $gt/$lt etc. Can you post the exact values being used for news[0]._id and news.slice(-1)[0]._id that are giving you the empty result?
However, i'm not sure that $gt/$lt is what you want here. It seems like what you need to do is extract the _ids of the news items, and then use that in a $in filter in your query on ratesm.

Resources