I have a parent and child schema that looks like:
schedule = Schema ({
from: Date,
to: Date
});
content = Schema ({
schedule: { type: Schema.ObjectId, ref: "schedule" }
name: String
});
My question is, how do I query Mongoose to return "all content, sorted by schedule.from date"?
You'll need to sort in two steps on the client, or store the date fields you want to sort on as embedded fields within the content object.
You're trying to do a collection join by using data from two collections. As MongoDB doesn't support a join, you'd need to populate the schedule field and then do a sort locally on the client. If you have very many documents, or want to do paging of data, this of course won't work.
The most efficient means would be to store the date fields in the content model so that you can perform sorting directly from a single document and collection, without the need of a join. While that may cause other issues with the schema design that you'd like to have, you may find this is the most efficient. The benefit of this denormalization process is that you can do sorting, filtering, etc. very easily and efficiently (especially if you've indexed the date fields for example).
schedule = Schema ({
from: Date,
to: Date
};
content = Schema ({
schedule: { type: Schema.ObjectId, ref: "schedule" },
schedule_data: {
from: Date,
to: Date
},
name: String
});
You could leave the schedule field in the content schema if you wanted to be able to quickly locate and update content documents (or if there were other less used or not needed for sorting/filtering).
In your case, you don't need a reference from one collection to another simply to store schedule.from & schedule.to.
Try the following :
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback () {
console.log('Mongoose connected to MongoDB\n');
content_sch = Schema ({
schedule: {
from: Date,
to: Date
},
name: String
});
var content = mongoose.model('content', content_sch);
contentObj = new content();
contentObj.schedule.from = Date.now();
contentObj.schedule.to = Date.now();
contentObj.name = 'Ryan Rife';
contentObj.save();
//Sorting; -1 to specify an ascending or 1 descending sort respectively
content.find({}).sort({'schedule.from': -1}).exec(function(err,contentDocs){
console.log(contentDocs);
});
});
You can do sorting in many ways another one is as follows which you could try:
content.find({}, null, {sort: {schedule.from: -1}}, function(err, contentDocs) {
//console.log(contentDocs);
});
Check this for more info
When to go for references to documents in other collections?
There are no joins in MongoDB but sometimes we still want references to documents in other collections (schema). Only then you need to use the ObjectId which refers to another schema and from that schema back to the parent.Example:
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }] //Here is a link to child Schema 'Story'
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' }, //Field which again refers to parent schema 'Person'
title : String,
fans : [{ type: Number, ref: 'Person' }] //Array which again refers to parent schema 'Person'
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
For more info check this mongoose populate docs
Related
I have the two models, entity and post, and I'm trying to create an auto incremented counter on post for each unique entity:
//entity
var entitySchema = mongoose.Schema({
name: String,
counter: Number,
});
//post
var postSchema = mongoose.Schema({
test: String,
entity: {
type: Schema.Types.ObjectId,
ref: 'entity'
},
ticketNumber: Number //this needs to auto increment starting at zero PER user, so entity A has a 1+, entity 2 has a 1+, etc
});
I can have a sequence on entity, check it every time I create a post and use it, but that could possibly have duplicates.
I found a post suggesting an even on pre post'save', but that wouldn't be unique to each entity, just unique overall.
Any way to get this working on the model itself / a better way of doing this?
You can use the npm package called mongoose-auto-increment.
Your connection would look like this:
var autoIncrement = require('mongoose-auto-increment');
var connection = mongoose.connect('YOUR CONNECTION');
autoIncrement.initialize(connection);
your Schema would look like this:
var postSchema = mongoose.Schema({
test: String,
entity: {
type: Schema.Types.ObjectId,
ref: 'entity'
},
ticketNumber: Number
});
postSchema.plugin(autoIncrement.plugin, { model: 'NAME YOUR MODEL', field: 'ticketNumber', startAt: 0, incrementBy: 1 });
so I'm been making a site that has comments section, messaging, profile and shopping for the user. I been wondering about when making a schema for those functions, is it better to have all in one schema like
userSchema {
name: String,
....
....
}
or have them seperate like
userSchema {
}
commentSchema {
}
gallerySchema {
}
No one can give you clear answer for this, everyone has different views.
Basically, It depends on your project's scalability
As I see your requirement for this project
You can create a single schema and use it as embedded form, but it's not a very good idea if you are scaling the app.
My recommendation is to create the separate schema for all the tasks which will be easy to debug,scaling the app and in readable form.
Edit
If you are creating separate schema and want to connect them then you can use populate on the basis of ObjectId
See the docs to populate collections
Example
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }]
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
Population
Story
.findOne({ title: 'Once upon a timex.' })
.populate('_creator')
.exec(function (err, story) {
if (err) return handleError(err);
console.log('The creator is %s', story._creator.name);
// prints "The creator is Aaron"
});
I am trying to make an API point that would do the following. I submit an Object ID in the path. The record with that ID is found. Then, the program looks into a certain field of this object. The field contains an ObjectID for another entry in the database. At last, I need to pull up that record and increment a certain field in it.
In short, I have a child->parent relationship between certain records and would like the ability of incrementing a certain field within the parent record by submitting the child's id to the API point.
Here is the code I had that did the basic child increment. How can I go about doing it for the parent?
router.get('/today/parent/up/:id', function(req, res){
var collection = db.get('Activity');
collection.update({
_id: req.params.id
},
{
$inc: {
"repetitions.today": 1,
"repetitions.total": 1
}
}, function(err, activity){
if (err) throw err;
res.json(activity);
});
})
First use mongo references, heres documenttion:
https://docs.mongodb.com/manual/reference/database-references/
here's mongoose documentation
http://mongoosejs.com/docs/2.7.x/docs/populate.html
Basically You need to do this:
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var PersonSchema = new Schema({
name : String
, age : Number
, stories : [{ type: Schema.ObjectId, ref: 'Story' }]
});
var StorySchema = new Schema({
_creator : { type: Schema.ObjectId, ref: 'Person' }
, title : String
, fans : [{ type: Schema.ObjectId, ref: 'Person' }]
});
var Story = mongoose.model('Story', StorySchema);
var Person = mongoose.model('Person', PersonSchema);
Then you could use .populate() method, and then you could extract your populated model and make changes and save them with .save(), but remember to use it in populated model, not the parent one. For ex. You've got author which contains reference to books, so you make request
author.findOne({'name': 'King'}).populate('books').exec((err, king) => {
let book0 = king.books[0];
book0.title = 'I need to change this one';
book0.save((err, data) => {
console.log('saved referenced object')
}
})
Allora, I'm using mongoose for the first time and I decided to create 2 schemes: the first one represents a user and the second one represents his enquires. Users have an array of enquires like:
var userSchema = new mongoose.Schema({
name: String,
enquires: { type : [Enquire.schema] , "default" : [] },
});
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
I see that if I search for an enquire and update its status, it doesn't update the same enquire on the user's array, meaning that they are different object. I don't want to save an array of IDs as it will be the same as a relational database, so I see only 1 solution which is forgetting about the enquire scheme and use only the User scheme. Is it the way mongoose works? For every relationship do I have to insert everything like nested object?
I think you should use references to achieve what you want to achieve.
For more information on mongoose references and populate see Mongoose Populate documentation.
Try this, It may help you.
User Schema :
var userSchema = new mongoose.Schema({
name: String,
enquires: [{ type : mongoose.Schema.Types.ObjectId , ref : 'Enquiry' }]//array of enquiries
});
var User = mongoose.model('User',userSchema );
module.exports = User;
Enquiry Schema :
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
var Enquiry = mongoose.model('Enquiry',enquireSchema );
module.exports = Enquiry ;
Working :
create a new Enquiry.
Push it's ID(_id) into user's enquires array.
var enquiry = new Enquiry();
enquiry.enquire = "Dummy enquiry";//set the enquiry
enquiry.save(function(err,result){
if(!err){
//push 'result._id' into users enquires array
}
});
whenever you update an enquiry, it will be automatically updated in
user's document.
use populate to retrieve user's enquiries.
You can embed sub documents (entity) which has id and is like a document or embed native array like a normal property.
And I think the correct definition for yours is :
var enquireSchema = new mongoose.Schema({
status: {type: String, 'default': 'pending'},
enquire: String,
});
var userSchema = new mongoose.Schema({
name: String,
enquires: { type : [enquireSchema] , "default" : [] },
});
If you use refs in embedded link then there are two separate collections and be like relational db's.
I want to use mongodb on my new project. That is first time, im using mongodb. In relational databases i was saving datas like:
tbl_country > id,name,created_at,etc..
tbl_city > id,country_id,name,created_at,etc...
tbl_user > id,name_surname,city_id,etc...
In this schema i can find a city's country, a user's country, etc... via using foreign keys.
Which way do you suggest to create a schema like this in best performance by nodejs w/ mongodb ?
You can still use foreign keys when you create your schemas. Please check this schemas as examples you have given.
var CountrySchema = new Schema({
name: String,
created_at: Date
});
var CitySchema = new Schema({
countryName: { type: mongoose.Schema.Types.ObjectId, ref: 'Country' },
created_at: Date
});
var UserSchema = new Schema({
name_surname: String,
city: { type: mongoose.Schema.Types.ObjectId, ref: 'City' }
})
mongoose.model('Country', CountrySchema);
mongoose.model('City', CitySchema);
mongoose.model('User', UserSchema);
and when you fetch data, you have to use 'populate' method. For instance:
City.find()
populate('countryName', 'name') // It will bring only name field
.exec(function(err, cities) {
})
Btw. _id s are automatically created by mongo for each data. So you do not need to add id field into your schemas. Hope it helps. Good luck