How to handle unique indexes with mongoose? - mongodb

The FAQ section of Mongoose 5 explitily says:
The unique option for schemas is convenient for development and documentation, but mongoose is not an index management solution.
This statement threw me off as I'm relatively new to Mongoose library. I'm making a basic model for User and adding a couple of tests for validation. Specifically validate no duplicate users are there.
The schema is simple
const schema = new Schema({
email: { type: String, required: true, unique: true },
...
Needless to say, my test fail:
const userA = new User({ email: 'a#a.com' });
const dupUserA = new User({ email: 'a#a.com' });
const promiseChain = userA.save().then(() => dupUserA.save());
expect(promiseChain).to.be.rejected // using chai-as-promised here
.then(err => {
// assertions about error message
});
The test fails cause the promise fulfills, meaning the save was successful.
I don't quite understand what Mongoose team means. I realize these schema are no database "migrations", but since the only example there is in the docs is some callback to the 'index' event, I'm lost.
How should I handle unique index? Is there a solution not to do them directly to the MongoDB through shell? Something that can reside in the codebase, equivalent to migrations?

Related

mongoose use model/scheme for multiple databases and multiple collections

I am looking for a way to use 1 schema for multiple databases and collections. I have 3 different databases and each holds 3 to 4 collections, which use all the same schema. I started just duplicating the schema for each collection and database, but that will add up to the amount of work. then I tried to export a function that returns the schema with set parameter, but I think that creates a new connection each time I call the function and eventually I get error. I can not find how to solve my problem the right way. Please someone can help me out a little.
What I currently try to use.
import mongoose from 'mongoose';
import Config from '../components/config.js';
const {database, localDatabase} = Config();
export default function(dex, network){
const db = mongoose.createConnection(localDatabase);
const transactions = db.useDb(network); // each network gets its own database
const txSchema = new mongoose.Schema({
uniquePoint:{
type: String,
required: true,
index: true,
unique : true,
},
version:{
type: String,
required: true,
},
network:{
type: String,
required: true,
},
},{collection: dex}); // each dex gets own collection
return transactions.model('TX', txSchema);
}
But this seems to give error after a while "MongoNetworkError: connect EADDRNOTAVAIL"

Cannot overwrite mongoose model once compiled with Nextjs

Before you close this question, I have read several forums that have the same question as I have but my issue is way different. Even when Im not trying to do anything, even save a model, it still gives me an error of:
cannot overwrite "mongoose" model once compiled
I have a feeling there is something wrong with my schemas because when it was still simpler, it worked fine but as I tried to make it more complex it started to give me that error. Here is my mongoose code:
import mongoose from 'mongoose'
const flashcardItemSchema = new mongoose.Schema({
term: {
type:String,
required: true,
min:1
},
description: {
type:String,
required:true,
min:1
}
});
const FlashcardItem = mongoose.model("flashcardItem", flashcardItemSchema);
const flashcardSetSchema = new mongoose.Schema({
title: {
type: String,
min: 1,
},
flashcards:[flashcardItemSchema],
})
const FlashcardSet = mongoose.model('flashcardSet', flashcardSetSchema )
export {FlashcardItem, FlashcardSet}
I connect to my database when the server runs, so it doesn't disconnect from time to time.
UPDATE
I realized that I'm using nextjs builtin api, meaning the api directory is inside the page directory. I only get the error once the pages get recompiled.
So it turns out that the error came from nextjs trying to remake the model every render. There is an answer here: Mongoose/NextJS - Model is not defined / Cannot overwrite model once compiled
but I thought the code was too long and all that fixed mine was just a single line. When trying to save a model in nextjs, it should be written like this:
const modelName = mongoose.models.modelName || mongoose.model('modelName', flashcardSetSchema )

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

How to Connect/Query Mongoose to an existing Database

I am working on trying to connect a Node/Express server to an existing MongoDB Database/Collection. I have already successfully connected to the database. However, I am having a tremendously difficult time setting up my models/schema to query.
The MongoDB is MongoDB Atlas and has one collection with over 800,000 documents. The name of the single collection is "delitosCollection".
I have tried the following to with no success:
var CrimeData = mongoose.model('DelitosCollection', new Schema({}),'delitosCollection');
mongoose.connection.on('open', function(ref){
console.log("connected to the mongo server");
CrimeData.find({}, (err,results) => {
if(err){
console.log("ERROR")
throw err
}
console.log("results: ", results.length)
} )
});
I know the connection is working as I am receiving the console.log with no errors. However, results.length is returning 0 when it should be over 800,000. Have spent way too many hours on this.
Create an empty schema for each collection you want to use
and then create a model to be used in your project
the model take 3 parameter
1)name of the model
2)schema name
3)collection name ( from mongodb atlas)
like that
const mongoose = require('mongoose');
mongoose.connect('mongodb uri')
const userSchema = new mongoose.Schema({});
const User = mongoose.model('User', userSchema, 'user');
then you can use the model normally
User.find({})
connection to mongo db
// Connect to mongoDB
mongoose.connect('mongodb://localhost/[yourDbName]',{useNewUrlParser:true})
.then(function(){
console.log('mongoDB connected');
})
.catch(function(){
console.log('Error :');
})
after that you will have to create your schema and then only you can query the database
create your schema like this
// Crimes Schema
const CrimeDetailsSchema= new Schema({
first_name: {
type: String,
required: true
},
last_name: {
type: String,
required: true
},
email: {
type: String,
required: true
}
});
const Profile = module.exports = mongoose.model('delitosCollection', CrimeDetailsSchema, 'delitosCollection');
after that create your queries
you can get an idea about that in mongoose documentation here
You can refer to the answer given below, just pass an empty object in schema
like db.model('users', new Schema({}))

How do you use Mongoose without defining a schema?

In previous versions of Mongoose (for node.js) there was an option to use it without defining a schema
var collection = mongoose.noSchema(db, "User");
But in the current version the "noSchema" function has been removed. My schemas are likely to change often and really don't fit in with a defined schema so is there a new way to use schema-less models in mongoose?
I think this is what are you looking for Mongoose Strict
option: strict
The strict option, (enabled by default), ensures that values added to our model instance that were not specified in our schema do not get saved to the db.
Note: Do not set to false unless you have good reason.
var thingSchema = new Schema({..}, { strict: false });
var Thing = mongoose.model('Thing', thingSchema);
var thing = new Thing({ iAmNotInTheSchema: true });
thing.save() // iAmNotInTheSchema is now saved to the db!!
Actually "Mixed" (Schema.Types.Mixed) mode appears to do exactly that in Mongoose...
it accepts a schema-less, freeform JS object - so whatever you can throw at it. It seems you have to trigger saves on that object manually afterwards, but it seems like a fair tradeoff.
Mixed
An "anything goes" SchemaType, its flexibility comes at a trade-off of
it being harder to maintain. Mixed is available either through
Schema.Types.Mixed or by passing an empty object literal. The
following are equivalent:
var Any = new Schema({ any: {} });
var Any = new Schema({ any: Schema.Types.Mixed });
Since it is a schema-less type, you can change the value to anything
else you like, but Mongoose loses the ability to auto detect and save
those changes. To "tell" Mongoose that the value of a Mixed type has
changed, call the .markModified(path) method of the document passing
the path to the Mixed type you just changed.
person.anything = { x: [3, 4, { y: "changed" }] };
person.markModified('anything');
person.save(); // anything will now get saved
Mongoose Schema Types
Hey Chris, take a look at Mongous. I was having the same issue with mongoose, as my Schemas change extremely frequently right now in development. Mongous allowed me to have the simplicity of Mongoose, while being able to loosely define and change my 'schemas'. I chose to simply build out standard JavaScript objects and store them in the database like so
function User(user){
this.name = user.name
, this.age = user.age
}
app.post('save/user', function(req,res,next){
var u = new User(req.body)
db('mydb.users').save(u)
res.send(200)
// that's it! You've saved a user
});
Far more simple than Mongoose, although I do believe you miss out on some cool middleware stuff like "pre". I didn't need any of that though. Hope this helps!!!
Here is the details description: [https://www.meanstack.site/2020/01/save-data-to-mongodb-without-defining.html][1]
const express = require('express')()
const mongoose = require('mongoose')
const bodyParser = require('body-parser')
const Schema = mongoose.Schema
express.post('/', async (req, res) => {
// strict false will allow you to save document which is coming from the req.body
const testCollectionSchema = new Schema({}, { strict: false })
const TestCollection = mongoose.model('test_collection', testCollectionSchema)
let body = req.body
const testCollectionData = new TestCollection(body)
await testCollectionData.save()
return res.send({
"msg": "Data Saved Successfully"
})
})
[1]: https://www.meanstack.site/2020/01/save-data-to-mongodb-without-defining.html
Note: The { strict: false } parameter will work for both create and update.
Its not possible anymore.
You can use Mongoose with the collections that have schema and the node driver or another mongo module for those schemaless ones.
https://groups.google.com/forum/#!msg/mongoose-orm/Bj9KTjI0NAQ/qSojYmoDwDYJ