How do I find a specific item in data array from Jade? - node.js

Not sure if this is good/bad practice but I have successfully serverd two sets of data (mongodb collections) to a jade page.
examples of these data mongoose Schemas are the following:
...
var personSchema = new Schema({
firstName: String,
lastName: String,
email: String,
city: String,
state: String,
zip: Number
});
module.exports = mongoose.model('person', personSchema);
and
...
var personQuoteSchema = new Schema({
_person : {
type: Schema.ObjectId,
ref: 'person'
},
quote: Number
});
module.exports = mongoose.model('quote', personQuoteSchema);
I have successfully served both collections to the jade tpls and they work fine. But now i'm confused for how to do what i'm trying to do:
I am building a page for the quotes that pulls in data for the person the quote is for. In the document for a single quote from the quotes collection, it has the ObjectId of the person from the persons collection.
This is what I have so far, but i'm stuck:
each quote in quotes
ul
li #{quote.quote}
li #{quote._person.firstName} #{quote._person.lastName}
Because it doesn't work. I need to find a way to go into the person document referenced in the quote document and get the firstName and lastName.
This is my first time asking for help on stackoverflow, please let me know if i'm missing anything that could help you help me.

The problem is that there's an extra step beyond just adding the ObjectId and ref into the Schema. As pointed out by #Molda, you have to use the .populate() function to make this work.
Once I saw the comment, I looked up the .populate() function, and this page does a great job explaining it.
So when I make the call, it has to look something like:
quote.find({}).populate({
path: '_person',
model: 'person'
}).exec(callback);

Related

How would i make the mongoose Schema dynamically according to the other fields value in node.js?

i want to define the schema dynamically according to the condition using mongoose
Schema
new mongoose.Schema({
type: String, //BASIC OR ADVANCE
// only for type = BASIC
name: String,
age: Number
/*
want these fields too but only if type = ADVANCE
email: String,
password: Number
PhoneNumber: String
*/
});
how would i achieve this kind of schema using mongoose.
it depends on what your approach to your database is. you can simply create two types with identifiers as Advance and Basic and use middleware to maintain the flow. Now to answer your question:
something like:
new mongoose.Schema({
type: String, //BASIC OR ADVANCE
// only for type = BASIC
name: String,
age: Number,
advance: []
And now you can check if advance is empty or not. Seriously it all depends on your approach, how you deal with the problem. Once a Schema is declared you can without the advance field, you can still save data like:
const MyModel = mongoose.model('Test', new Schema({ name: String }));
const doc = new MyModel();
doc.advance = {
email: "test#test.com",
password: 1234,
PhoneNumber: 1234
}
doc.save();
But with this structure if you want to know the Schema, you'll think that in your file it is only name and age and later when you start exploring, you'll find out that you are doing something like this and using a proper structure.
Think of moongoose documents as JavaScript Objects, there is a reason it is known as non-Structured data. Hope this explanation helps.

Mongoose search for an object's value in referenced property (subdocument)

I have two schemas:
var ShelfSchema = new Schema({
...
tags: [{
type: Schema.Types.ObjectId,
ref: 'Tag'
}]
});
var TagSchema = new Schema({
name: {
type: String,
unique: true,
required: true
}
});
I would like to search for all Shelves where the tags array has a tag with a specific value.
I have tried using:
modelShelf.find({tags 'tags.name': 'mytag'})...
but it does not work. It always returns an empty array.
Any idea?
Looking at db each Shelf instance links only the objectID of the tags.
I have used references because I need to work also with Tag(s) entities.
In mongoDB you essentially can't do this directly as queries target a single collection at a time. Recently there were added new features which allow some kind of join when using the aggregation framework but for your needs that is not necessary.
From your schemas I see that the tags' names are unique so you can first fetch your desired tag with something like
modelTag.find({name: 'mytag'})
in order to get the tag's ID and then query your shelf collection for this tag ID
modelShelf.find({tags: tagId})

Easy way to reference Documents in Mongoose

In my application I have a User Collection. Many of my other collections have an Author (an author contains ONLY the user._id and the user.name), for example my Post Collection. Since I normally only need the _id and the name to display e.g. my posts on the UI.
This works fine, and seems like a good approach, since now everytime I deal with posts I don`t have to load the whole user Object from the database - I can only load my post.author.userId/post.author.name.
Now my problem: A user changes his or her name. Obviously all my Author Objects scattered around in my database still have the old author.
Questions:
is my approuch solid, or should I only reference the userId everywhere I need it?
If I'd go for this solution I'd remove my Author Model and would need to make a User database call everytime I want to display the current Users`s name.
If I leave my Author as is, what would be a good way to implement a solution for situations like the user.name change?
I could write a service which checks every model which has Authors of the current user._id and updates them of course, but this sounds very tedious. Although I'm not sure there's a better solution.
Any pro tipps on how I should deal with problems like this in the future?
Yes, sometime database are good to recorded at modular style. But You shouldn't do separating collection for user/author such as
At that time if you use mongoose as driver you can use populate to get user schema data.
Example, I modeling user, author, post that.
var UserSchema = new mongoose.Schema({
type: { type: String, default: "user", enum: ["user", "author"], required: true },
name: { type: String },
// Author specific values
joinedAt: { type: Date }
});
var User = mongoose.model("User", UserSchema);
var PostSchema = new mongoose.Schema({
author: { type: mongoose.Scheam.Types.ObjectId, ref: "User" },
content: { type: String }
});
var Post = mongoose.model("Post", PostSchema);
In this style, Post are separated model and have to save like that. Something like if you want to query a post including author's name, you can use populate at mongoose.
Post.findOne().populate("author").exce(function(err, post) {
if(err)
// do error handling
if(post){
console.log(post.author.type) // author
}
});
One solution is save only id in Author collection, using Ref on the User collection, and populate each time to get user's name from the User collection.
var User = {
name: String,
//other fields
}
var Author = {
userId: {
type: String,
ref: "User"
}
}
Another solution is when updating name in User collection, update all names in Author collection.
I think first solution will be better.

How do I reference ObjectID in another collection in MongoDB & Node?

I'm fairly new to this, so bear with me, however I have 2 collections. One called photos and another called users.
In Node, I am taking the data and putting it into my MongoDB using mongoose. I've got this working fine with my Schema:
var picSchema = new Schema({
uid: String,
pid: String,
oFile: String
});
What I want to do though is for the uid, I want to add the ObjectId for the user uploading the photo. I can pass this as a String, however I thought that I would have had to have the field set as an ObjectId, but seems I cannot do this?
Unless I am missing something, I might as well just add the username in there and use that as a reference?
Use mongoose.Schema.Types.ObjectId to populate the field with an ObjectId. In this case, you would use User (or whatever the name of your User schema is).
var picSchema = new Schema({
uid: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},
pid: String,
oFile: String
});
Further to this, you can also use the Mongoose method Populate if you wish to expand the User document within a Pic document. For example:
Pic.find({})
.populate('uid')
.exec(function(err, pic) {
console.log(pic);
// do something
});

How to update a mongodb/mongoose schema from a single value field to a multi value field

I have a schema defined in Mongoose like this:
var Stuff = new Schema({
href: String,
thing: Number,
});
But now the "thing" field is more complicated than a single number, so I'd like to update my model make "thing" have embedded fields:
var Stuff = new Schema({
href: String,
thing: { thinglabel: String,
thingvalue: Number}
});
I'm wondering if there is an elegant way to do this. For the time being, I've hacked around this problem by adding a second field but I was thinking that there might be a better solution the next time I run into this problem.

Resources