mongoose autoincrement counter per unique value - node.js

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 });

Related

Foreign Key relationship in Mongoose with customized key

I am kinda new to MongoDB and nextjs space. I have 2 schemas :
User
Fav Dishes
Schema for user is :
import mongoose from 'mongoose'
require('mongoose-type-url');
const UserSchema = new mongoose.Schema({
name: { type: String, unique: true}
address: {type: String},
},{ timestamps: {} })
UserSchema.pre("save", function (next) {
let brand = this;
user.name = user.name.replace(/ /g,"_")
next();
})
Another schema is
const FavDish = new mongoose.Schema({
name: String,
user: {type: mongoose.Schema.Types.ObjectId, ref : 'User'})
So the reference in FavDish collection want to use is userName instead mongo created ObjectID. and while populating the data for FavDish get the details for user as well. How can i achieve this? please help me.
So, first of all, if the relationship between the Schemas are 1to1, consider embedding the favDish inside the user Schema and not referencing (each user has a name, an address and a favDish name).
So the userSchema will look like:
const UserSchema = new mongoose.Schema({
name: { type: String, unique: true}
address: String,
fevDish: String
},{ timestamps: {} })
If you want to keep it like the way you wanted (with two schemas and referencing) you will need to populate after finding the fevDish:
const populatedDish = await FavDishModel.findOne({name: 'pasta'}).populate('user');
/**
* populatedDish - {
* name: 'pasta',
* user: {
* name: 'Justin',
* address: 'NY'
* }
* }
*
*/
this way while finding the dish you want, mongoose will put the user object instead of the _id of it.
Hope that helps.

mongoose-schema - are both children array + parent doc's ID necessary?

I'm using a couple of one-to-many models and was wondering what the advantage of having both an array of "children" ObjectID()s and a "parent" model's ObjectID() in the child is. For example:
// a client will have a new card every ten visits
var ClientSchema = new Schema({
first_name: String,
last_name: String,
email: String,
cards: [] // ObjectID()s, <--- is this necessary?
});
var CardSchema = new Schema({
client: ObjectID(), // <--- or is this enough?
visits: []
});
I think the client: ObjectID() should do the trick in most cases, specially with the Population options Mongoose offers.
It suffices to store the reference ObjectId in one of the documents.
As you can read in the documentation or in this answer, the reference field needs a type and a ref. The name of field is arbitrary. Once you have done this and registered your models, you can use the models to populate your queries.
var clientSchema = new Schema({
first_name: String,
last_name: String,
email: String
});
var cardSchema = new Schema({
client: {
type: Schema.Types.ObjectId,
ref: 'client'
}
});
// models
var Card = mongoose.model('Card', cardSchema);
var Client = mongoose.model('Client', clientSchema);
Yet, it could be helpful to store an array of ObjectId's. However, this also creates a huge window for mistakes. A mismatch of foreign key and primary key, in SQL dialect. You can always do a count query if you need to count. I would say, do either the above or do this:
var clientSchema = new Schema({
first_name: String,
last_name: String,
email: String,
cards: [
{
type: Schema.Types.ObjectId,
ref: 'card'
}
]
});
var cardSchema = new Schema({
card_name: String
});
// models
var Card = mongoose.model('Card', cardSchema);
var Client = mongoose.model('Client', clientSchema);

mongoose schema, is it better to have one or have several for different tasks?

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"
});

how to implement the function like left join of mysql in mongoose

I am going to implement the function like left join of mysql in mongoose.
the date is
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var personSchema = Schema({
_id : Number,
name : String
});
var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String
});
var personProfile = Schema({
userid : {type: Number, ref: 'Person'},
birthday: Date,
profilelink: String,
email: String
});
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
var personProfile = mongoose.model('Personprofile', personProfile );
I am going to display the Story model with the user profile.
We have to get the profile info with the _creator of story and the userid of personProfile
How can I get the info using mongoose query?
Thanks Nelis
What your are trying to do is not possible because there is no join statement on mongodb.
You can achieve this in two ways:
1 - By DBRefs: Changing your Schema to one that include all the user info and do not split them in two different schemas as you are doing, see denormalized. Then you can use the Population function to get all the persons data.
2 - By Manual references: The second solution is to make a second call to the database getting the personProfile data using the userid as a filter.
Example 1:
This way you can get all persons data without a second call to the database.
var personSchema = Schema({
_id : Number,
name : String,
birthday: Date,
profilelink: String,
email: String
});
var storySchema = Schema({
_creator : { type : Schema.Types.ObjectId, ref: 'Person' },
title : String
});
Story
.find()
.populate(['_creator'])
.exec(function(err, stories) {
//do your stuff here
}
Notice that I'm using the type Schema.Types.ObjectId and not the Number. This way, you can assign a new value to _creator passing either the _id or the person object and the mongoose will convert the object to its _id. For example, you can post something like
{
_creator : {
_id : 123123123123,
name : 'Foo',
birthday: '0000-00-00',
profilelink: 'http://foo.bar',
email: 'foo#bar.com'
},
title : 'Mr'
}
... and the mongoose will convert to
{
_creator : 123123123123,
title : 'Mr'
}
Example 2:
This way your data still normalized and you can get all the persons data with a second call.
Story
.find()
.exec(function(err, stories) {
var arrayLength = stories.length;
for (var i = 0; i < arrayLength; i++) {
var story = stories[i];
personProfile.findById(story._creator, function (err, person) {
story._creator = person;
}
};
// do your stuff here
}

Mongoose sort by child value

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

Resources