Is it possible to populate without `_id`? - javascript

I Set manually an uid to each item in my collections...I Want To Know It's Possible that I use uid for populate?
I Dont Want Use from '_id' because Have Many collections In My DB And should change many things...somthing like this :
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var PersonSchema = new Schema({
name : String
, age : Number
, stories : [{ type: String, ref: 'Story' }]
});
var StorySchema = new Schema({
_creator : { type: String, ref: 'Person' }
, title : String
, fans : [{ type: String, ref: 'Person' }]
});
var Story = mongoose.model('Story', StorySchema);
var Person = mongoose.model('Person', PersonSchema);

No, it is not possible to have a mongodb document without '_id' , if you want to avoid duplication of ids, you can put uid in '_id' before saving the document.
If you keep uid seperately, '_id' will get autopopulated as ObjectId.

Here is a clear example of how to do it (https://mongoosejs.com/docs/populate.html):
Story.
find(...).
populate({
path: 'fans',
select: 'name -_id' // <---------------'-_id' exclude _id field.
}).
exec();

Related

What is a virtual for an URL in Mongoose?

I am currently following a tutorial on implementing a database (Mongoose) in a simple website created using Express-framework. I do not have any problem understanding the concept of models, but I fail to make sense of the lines following the comment "Virtual for book's URL" in the code attached. How do these lines operate, and what role does having a virtual property have in this context?
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var BookSchema = new Schema(
{
title: {type: String, required: true},
author: {type: Schema.Types.ObjectId, ref: 'Author', required: true},
summary: {type: String, required: true},
isbn: {type: String, required: true},
genre: [{type: Schema.Types.ObjectId, ref: 'Genre'}]
}
);
// Virtual for book's URL
BookSchema
.virtual('url')
.get(function () {
return '/catalog/book/' + this._id;
});
//Export model
module.exports = mongoose.model('Book', BookSchema);
Virtuals are typically used for computed properties on documents.
BookSchema
// 'url' is the name of the virtual
.virtual('url')
.get(function () {
// you are computing dynamic url
return '/catalog/book/' + this._id;
});
Important thing about virtuals is it does not store anything on database. Imagine you stored "name" and "lastname" but you want to display fullname without having "fullname" column. You would be using repeated data on database if you add fullname property to your schema, this will slow down and will also cost you. Instead you write virtual:
YourSchema.get(function(){
return this.firstname + ' ' + this.lastname
})
You can also go one step further and return fullname property as it is in a column in database. mongoose Schema takes options object
let options={
toJSON:{
virtuals: true
}
}
set the virtual
let YourSchemaVirtual=YourSchema.virtual('fullname')
now when querying the database, get the collection
YourModel.findOne({firstname:"name"}).exec(function(err,user){
res.send(user)
})
In return value you will see fullname field computed as this.firstname + ' ' + this.lastname even though you have no fullname stored in database.

Nested elements in mongoose modelling

I have to create a database in this format:
I have tried to do it like this :
var mongoose = require("mongoose")
, Schema = mongoose.Schema;
var categorySchema = new Schema({
_id: String,
subcategory: {
type: Schema.Types.ObjectId,
ref: "Subcategory"
},
id: String,
name: String,
page_description: String,
page_title: String,
parent_category: String,
c_showInMenu: Boolean
});
module.exports = mongoose.model("Category", categorySchema);
And I did the same for every subcategory, but I named them "Subcategory" and "SubsubCategory". I'm pretty much a newbie, I've read the documentation on mongoose and I've also followed an online course. I feel like I know something, but I don't understand it properly or that my logic behind it is wrong.
Also, I've managed to find this about recursive elements in Schemas, but I don't fully understand it and I don't know how to implement it to my database: Recursive elements in Schema : Mongoose modelling
I checked your code and collection image.
Here's what you are doing wrong.
You don't need to declare _id field, it's auto-generated.
Keep the column names same as they are in the given collection image.
This should be your schema declaration. Note that, this schema is for the whole collection and not just for categories array.
var mongoose = require("mongoose"),
Schema = mongoose.Schema;
var mainSchema = new Schema({
categories: [ {
id: String,
image: String,
name: String,
page_description: String,
page_title: String,
parent_category_id: String,
c_showInMenu: Boolean
}]
});
This is just an example of the schema, please add necessary changes to it.

Adding a list of objectIds to an array in a collection (ref)

I have a user and doctor collection/model. here's the file it is in
module.exports = function(mongoose){
var User = mongoose.Schema({
username: {type : String, unique : true},
password : String,
nameOfOrg : String,
workers : [],
doctors : [{type : mongoose.Schema.Types.ObjectId, ref : Doctor}],
patients : [{type : mongoose.Schema.Types.ObjectId, ref : Patient}]
})
var Doctor = mongoose.Schema({
name : String,
address : String,
parentOrg :[{type : mongoose.Schema.Types.ObjectId, ref : User}],
patients :[{type : mongoose.Schema.Types.ObjectId, ref : Patient}]
})
var Patient = mongoose.Schema({
name : String,
DOS : String,
parentOrg :[{type : mongoose.Schema.Types.ObjectId, ref : User}],
parentDoctor : [{type : mongoose.Schema.Types.ObjectId, ref : User}]
})
var models = {
User : mongoose.model("user", User),
Doctor : mongoose.model("doctor", Doctor),
Patient : mongoose.model("patient", Patient)
};
return models;
}
I have a route handler like doctor/:name every time I go there I put the param in the db so doctor/doc1 adds doc1 to the name field in the doctors collection. Well every time that happens Im trying to add the objectId of this newly created document to the doctors array in the users collection. I think that is what you are supposed to do to use populate in the future to keep data separate in different collections then bring the appropriate parts together. Any ways I'm having problems adding the doctors ID to the doctors array in the users collection when I go to the route. here is the routing app.js code
mongoose.connect("mongodb://localhost/pop3");
var models = require("./db")(mongoose);
app.get("/:name", function(req, res){
var user1 = new models.User({"username": req.params.name})
user1.save(function(err, doc){
if(err){
console.log(err)
}
console.log(doc)
res.send(doc)
app.locals.user = doc
})
})
app.get("/doctor/:name", function(req, res){
var doctor = new models.Doctor({"name" : req.params.name, "parentOrg" : app.locals.user._id})
// app.locals.user.doctors.push(app.locals.user._id)
models.User.findOne({"username": app.locals.user.username}).push(doctor._id)
doctor.save(function(err, doc){
if(err){
console.log(err)
}
console.log(doc)
res.send(doc)
})
});
I tried to folow the mongoose doc on populate they show to do a similar thing I think by demoing this:
aaron.stories.push(story1);
aaron.save(callback);
I guess arron will be my user that was just saved.
stories will be the doctors field and
story1 will be the doctor.
I just couldn't do it
EDIT:: I get this error in the browser window:
TypeError: models.User.findOne(...).push is not a function

Mongoose.js: force always populate

Is there a way to instruct model to populate ALWAYS a certain field?
Something like, to have "field" populated in any find query:
{field: Schema.ObjectId, ref: 'Ref', populate: true}
?
With Mongoose 4.0, you can use Query Hooks in order to autopopulate whatever you want.
Below example is from introduction document by Valeri Karpov.
Definition of Schemas:
var personSchema = new mongoose.Schema({
name: String
});
var bandSchema = new mongoose.Schema({
name: String,
lead: { type: mongoose.Schema.Types.ObjectId, ref: 'person' }
});
var Person = mongoose.model('person', personSchema, 'people');
var Band = mongoose.model('band', bandSchema, 'bands');
var axl = new Person({ name: 'Axl Rose' });
var gnr = new Band({ name: "Guns N' Roses", lead: axl._id });
Query Hook to autopopulate:
var autoPopulateLead = function(next) {
this.populate('lead');
next();
};
bandSchema.
pre('findOne', autoPopulateLead).
pre('find', autoPopulateLead);
var Band = mongoose.model('band', bandSchema, 'bands');
this plugin is a solution to your question:
https://www.npmjs.com/package/mongoose-autopopulate
I use query hook to autopopulate, but it not works with create() and save() for modified fields.
This is my code:
var autoPopulate = function(next) {
this.populate('updated_by','name').populate('created_by','name');
next();
};
ProjectSchema.pre('findOne', autoPopulate);
ProjectSchema.pre('find', autoPopulate);
If I update Project only created_by is populated
If I create new Project both created_by and updated_by are not populated.
find and findOne works with no problems.
What should I do to always populate both: created_by and updated_by?

MongooseJS schema relation

I have MongooseJS schema as follow:
var UserSchema = new Schema({
name : String,
app_key : String,
app_secret : String,
tasks : [{ type : Schema.ObjectId,
ref : 'Task'}]
})
var ActionSchema = new Schema({
name : String,
description : String,
module : String
})
var enumTaskState = ['New', 'Indexing', 'Idle', 'In Queue', 'Working'];
var TaskSchema = new Schema({
name : String,
lastPerformed : Date,
folder : String,
actions : [{type : Schema.ObjectId,
ref : 'Task'}],
user : { type : Schema.ObjectId,
ref : 'User'},
status : { type : String,
enum : enumTaskState,
default : 'New'}
})
Problem is, when I set a task's user, do I manually have to go to the user and add a task there too? This seems like extra work (redundancy), is there an option in mongoosejs that will allow me to specify the relations it will handle everything by itself?
Thanks.
MongoDB is not a relational database, it is a document based based database.
You can get a user's list of tasks by querying the TaskSchema and looking for the user you want. Just make sure to add an index so it will be a fast query:
user: {type: Schema.ObjectId, ref: 'User', index: true}
To elaborate on emostar's answer:
You're trying to use MongoDB like a relational database. You're giving Users a list of Tasks, but each Task is referencing a User. In a typical MongoDB schema, you'd figure out how you want to use the models in your app and just embed the documents where it makes sense (e.g. if Users contains an array of Tasks, there's no need for a task to have a reference to it's owner--just look at the User that owns the collection).

Categories