Relations in NoSql using mongoDB and Mongoose - mongodb

Ok, im comming from an SQL background and I am just getting my hands dirty using MongoDB and Mongoose.
I have two simple models:
CAR:
let mongoose = require('mongoose');
let carsSchema = new mongoose.Schema({
brand: String,
specfifications: [String],
image: String
});
module.exports = mongoose.model('Car', carSchema);
Driver
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let driverSchema = new mongoose.Schema({
name: String,
cars: [{ type: Schema.Types.ObjectId, ref: 'Car' }]
});
module.exports = mongoose.model('Driver', driverSchema);
From what I can understand, this seems to be a proper way of handling a one-to-many-relationship where one car can be used by many drivers.
Now I need to add a class called Races which will be used for saving the results for spacific driver in a specific car.
Thinking in SQL I would do something like this:
let mongoose = require('mongoose');
let raceSchema = new mongoose.Schema({
totaltime: String,
laptime: String,
driver: { type: Schema.Types.ObjectId, ref: 'Driver' },
car: { type: Schema.Types.ObjectId, ref: 'Car' }
});
module.exports = mongoose.model('Race', raceSchema);
Would you consider this to be to correct approach in NoSql or am I forcing my SQL-way of thinking into NoSQL?

the answer is it depends
MongoDB or NoSQL theory says if all related data are in one document, then your query will run faster as they will be stored together. So, in most cases we would prefer one single model for both Car and Driver
If you do not query car and drivers together in most of your queries (chances for which would be rare), then what you did is also correct.
Also, MongoDB has a limitation on size of document i.e. 16 MB if you think the cost of storing them together can go beyond 16MB then what you did is correct. However, there is an alternate solution i.e. GridFS which stores the documents into chunks and overcomes this limitation

Related

MongoDb: In a many to many relation, when does it make sense to make the ids of both models in the definition of the other model

I have this relation:
User has many courses
I have implemented it by integrating the user_id in the definition of the Course model:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
//Create Schema
const CourseSchema = new Schema({
user: {
//This will associate the user by his id
type: Schema.Types.ObjectId,
ref: "users",
},
date: {
type: Date,
default: Date.now,
},
});
module.exports = Course = mongoose.model("course", CourseSchema);
This way, if I want to get the courses created by a user X, I just use his id and look it up in the courses documents.
I thought with a big data base, this operation may be costly.
So I should add the course_id, to an array property called courses in the User model:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
courses: [
{
type: Schema.Types.ObjectId,
ref: "course",
},
],
});
module.exports = User = mongoose.model("users", UserSchema);
This way, I can simply populate that array with the .populate operation, instead of going with the appraoach mentioned above.
I would like to know if my way of thinking makes sense.
And whether there other reasons for me to add the course_id, to courses property in the User model.
both approach is correctly I have seen both methods that uses
but when you want to using populate, you should update two collections(users and courses) when you want to insert a new Course, so you should use transaction because if one was updated and the other did not(An error occurred) rollback be done
the first thing to understand about mongoose population is that it is not magic, but just a convenience method that allows you to retrieve related information without doing it all yourself
if user id be index in couresSchema you can find() all courses very fast,
but the generally recommendation is to consider the data usage patterns of your application and choose what is best

Problem with FreeCodeCamp's "MongoDB and Mongoose - Create a Model" Challenge

I am doing FreeCodeCamp's "MongoDB and Mongoose - Create a Model" challenge. I have submitted by code. However, I am getting this error:
Creating an instance from a mongoose schema should succeed
Here are my codes:
let mongoose = require('mongoose')
mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true });
let personSchema = new mongoose.Schema({
name: {type: String, required: true},
age: Number,
favoriteFoods: [String]
});
let Person = mongoose.model('Person', personSchema);
Have I made any mistake?
Since you are submitting this code to FCC server, you don't need to connect to db by your own. They must be having connections already made to db. You just have to provide the right implementation of Person model. IMO Since you had that line in your submission, code was breaking at that line and subsequent lines were not getting executed. Hence you were getting this error. Creating an instance from a mongoose schema should succeed
Try this -
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let personSchema = new Schema({
name: {type: String, required: true},
age: Number,
favoriteFoods: [String]
});
let Person = mongoose.model('Person', personSchema);
The following code worked for me after trying many different things suggested on different posts/blogs on the Internet.
require('dotenv').config();
//To-Do # 1: Install & Set up mongoose */
const mongoose = require('mongoose');
mongoose.connect(process.env.MONGO_URI);
//To-Do # 2: Create a Model
const personSchema = new mongoose.Schema({
name: { type: String, required: true },
age: Number,
favoriteFoods: [String]
});
const Person = mongoose.model('Person', personSchema);
I still could not find what was the problem as I tried to copy and paste exactly the code given in the solution to the problem suggested by free code camp and even that did not work. I was using replit and perhaps there must be some problem when the free code camp tests interact with the liver server of replit but some expert should answer the problem in detail to save time for other people.
It appears that the problem occurs because a code below is trying to redeclare the "Person" variable (After making it a const). If you look at the boilerplate code on Replit, there were some codes present there already and part of this code has the following:
let Person;
Simply commenting this line out worked for me.

Store data in ES and not on MongoDB using mongoosastic

I am trying to build a search engine project using mongoosastic and was wondering if there was a way to store specific data fields only on elasticsearch and not on MongoDB as this would basically make it duplication of data.
For example we can use the es_indexed to make sure elasticsearch indexes the data and stores it to MongoDB but is there something similar which can make sure elasticsearch indexes the data but MongoDb does not store it.
var mongoose = require('mongoose')
, mongoosastic = require('mongoosastic')
, Schema = mongoose.Schema
var User = new Schema({
name: {type:String, es_indexed:true}
, email: String
, city: String
, comments: {type:[Comment], es_indexed:true}
})
User.plugin(mongoosastic)
I was checking the same with mongoose as well but it wasn't working.
How can i achieve this?
Using select: false will insert the data only to elasticsearch and not mongodb
var mongoose = require('mongoose')
, mongoosastic = require('mongoosastic')
, Schema = mongoose.Schema
var User = new Schema({
name: {type:String, es_indexed:true}
, email: String
, city: String
, comments: {type:[Comment], es_indexed:true, select: false}
})
User.plugin(mongoosastic)

Mongoose mixed SchemaType

I couldn't understand that for what purpose mongoose schemaType is used for. If someone could explain it will be helpful.
I'm have to reference another schema from a schema i want to know if we can get the details of all schema together when we do a findOne() on mongoose.
mixed schema means whatever you want the type to be. if you input a String, Number, Date, mongoose will let you do that. However according to documentation, mongoose ref does not work with mixed.
Note: ObjectId, Number, String, and Buffer are valid for use as refs.
if you use mixed, and ref it, you won't be able to query it back.
If you start all over(delete the database and reinsert again), use ObjectId instead of Mixed.
var storySchema = Schema({
author : { type: ObjectId, ref: 'Person' },
});
If you wish to retain old database, the best way is to change mixed to string
var storySchema = Schema({
author : { type: String, ref: 'Person' },
});

Mongoose Reference for simple code reference values?

I'm designing a MongoDB schema to save a fairly large/nested document. I'm planning on embedding as much as possible into a single document, but wasn't sure what to do with code/lookup values. For example, if we have a code table representing "priority", with the possible values being:
low
medium
high
Is this something I should use a Mongoose reference for, and create a simple document to hold priority, eg something like:
var PrioritySchema = new Schema({
description: String
});
This would then be referenced with something like the following:
var AnotherSchema = new Schema({
name: String,
active: Boolean,
priority: { type: String, ref: 'Priority' }
});
Or is this overkill? The thing I want to avoid is directly storing these "descriptions" in the main/overall model, then having a requirement change sometime in the future. For example, someone decides that instead of "medium", we need to call it "somewhat". In that situation, I assume I'd be stuck doing some sort of data migration?
you can do this :
var PrioritySchema = new Schema({
description: String
});
and this
var AnotherSchema = new Schema({
name: String,
active: Boolean,
priority: { PrioritySchema }
});
But if you want what you described further I would advise you to do this instead :
var AnotherSchema = new Schema({
name: String,
active: Boolean,
priority: { type: Schema.Types.ObjectId, ref: 'Priority' } // see this : Schema.Types.ObjectId != String
});
Let's make it simple if you need those values to be cross-documents you need to use reference. If the values are only existing because of the parent document then you can choose embing.
For more information read this :
http://mongoosejs.com/docs/2.7.x/docs/embedded-documents.html
FYI : I used to struggle a lot with this. If you follow the path of embing all nested sub-document you will face a lot of "What Why I can't do that :'(. At the end I choosed the referencing way I felt more confortable with it. embing != referencing.