mongoose schema creation - node.js

I've just started with mongoose. I have a creation script with mongoose that creates the schemas and db with sample data.
Now I write the actual application. Do I need to create the schema object each time my application runs, or is it already available somehow?
In other words do I need to run this code in every app that uses mongoose to access the db or just the first time:
var Comments = new Schema({
title : String
, body : String
, date : Date
});
How would the answer change if I have setters/validations/etc?

One defines Schema so application understands how to map data from the MongoDB into JavaScript objects. Schema is a part of application. It has nothing to do with database. It only maps database into JavaScript objects. So yes - if you want to have nice mapping you need to run this code in every application that needs it. It also applies to getters/setters/validations/etc.
Note however that doing this:
var mongoose = require('mongoose');
var Schema = mongoose.Schema; // <-- EDIT: missing in the original post
var Comments = new Schema({
title : String
, body : String
, date : Date
});
mongoose.model("Comments", Comments);
will register Schema globaly. This means that if the application you are running is using some exterior module, then in this module you can simply use
var mongoose = require('mongoose');
var Comments = mongoose.model("Comments");
Comments.find(function(err, comments) {
// some code here
});
(note that you actually need to register the Schema before using this code, otherwise an exception will be thrown).
However all of this works only inside one node session, so if you are running another node app which needs the access to the Schema, then you need to call the registration code. So it is a good idea to define all Schemas in separate files, for example comments.js may look like this
var mongoose = require('mongoose');
var Schema = mongoose.Schema; // <-- EDIT: missing in the original post
module.exports = function() {
var Comments = new Schema({
title : String
, body : String
, date : Date
});
mongoose.model("Comments", Comments);
};
then create file models.js which may look like this
var models = ['comments.js', 'someothermodel.js', ...];
exports.initialize = function() {
var l = models.length;
for (var i = 0; i < l; i++) {
require(models[i])();
}
};
Now calling require('models.js').initialize(); will initialize all of your Schemas for a given node session.

You do need to run this initialization code every time you run your app to register your app's Schemas with mongoose.
When your app ends, mongoose does not store your Schema(s). So, the next time you run an app that uses a Schema, you need to register your Schema(s) again.
However, it's fairly easy to set up your app to do so.
Here are two links to code that demonstrates how one can initialize schemas in mongoose. The first is in JavaScript, the second is in CoffeeScript.
https://github.com/fbeshears/register_models
https://github.com/fbeshears/register_coffee_models
The JavaScript demos is just one app.
The CoffeeScript code has two separate apps. The first stores documents with MongoDB, the second finds and displays the documents stored by the first app.

Related

Using a Mongoose model defined in another file returns Undefined

It seems pretty clear that defining a model in one file but using it in another is common practice. I don't know why I'm having so much trouble getting it to work. I spent the morning rewriting my simple MongoDB app to follow what I thought was a dead simple example. I'm just structuring it like the top answer with the added convenience that the file where I define the Schema and Model and access the Model are in the same folder (because the project is so small and I'm just learning MongoDB). I think part of the problem as I tried researching solutions is that other examples really complex to follow. The DB connects as expected and I can work in the ManageDB.js file fine, but of course want to keep the project organized, even at my small scale. (The server.js file in the directory above connects before this code executes.)
What other things can I try to troubleshoot this MongoDB application?
// src/ManageDB.js
const mongoose = require('mongoose');
const devTweetRecordsModel = new mongoose.Schema({
time: Date,
text: String,
source: String,
positive: Number,
negative: Number,
});
var tweetdb = mongoose.model('DevTweetDB', devTweetRecordsModel);
module.exports = {
tweetdb: tweetdb
};
// src/TwitterAPI.js
const mongoose = require('mongoose');
var tweetdb = require('../src/ManageDB').tweetdb;
console.log(tweetdb); // Returns undefined
After defining a model-schema in mongoose you should assign it as mongoose.model
as you can see in the documentation.
https://mongoosejs.com/docs/models.html
const schema = new mongoose.Schema({ name: 'string', size: 'string' });
const Tank = mongoose.model('Tank', schema);
When you call mongoose.model() on a schema, Mongoose compiles a model for you.
and then you can use it by requiring it in another file.
const Model= require('./../models/modelName');
I solved it a way I hadn't seen suggested anywhere so I will post here for completeness. The solution was very sensitivity to how I exported it and brought it into the other JS file.
// Model.js
module.exports = mongoose.model('DevTweetDB', devTweetRecordsModel);
// TwitterAPI.js
var tweetdb = require('../models/tweetdb');
console.log(tweetdb);
// Returns the object as expected:
// Model { DevTweetDB }

node.js mongoose multiple database across project using same schema

I want to make use of multiple databases in a project, but I am having difficulty in calling the
secondary databases across many route controllers. I do not want to close connection to the main databases
the current method which I have used to insert data into multiple controllers I believe is not efficient
enough i.e.
------>> all these are called every time a file needs to connect to the secondary database
----------------------------------------------------------------------------------------|
var mongoose = require('mongoose'); |
var mongooseConnect = mongoose.createConnection('mongodb://localhost/27017/'+dbName); |
|
require('./models'); |
var modelData = mongooseConnect.model('models'); |
----------------------------------------------------------------------------------------|
modelData.save()
I am looking for a method which would allow me to
connect to the secondary database once and call it anytime i want to across the controllers
combine the above code into a one line code
I have called the main database through the normal means which is
route.js
var mongoose = require('mongoose');
mongoose.connect(mongodbhost/maindb)
then in the schema I just simply require mongoose before using it in the schema. and only the schema is called in the
route controllers.
Any help would be appreciated
You can use the same schema in multiple database but you would need to create the connections to both databases. Here's how you can do it:
const conn1 = mongoose.createConnection('mongodb://localhost:27017/test1');
const conn2 = mongoose.createConnection('mongodb://localhost:27017/test2');
const TestSchema = require('./TestSchema');
var TestModelDb1 = conn1.model('Model', TestSchema);
var TestModelDb2 = conn2.model('Model', TestSchema);

Mongoose _id affected before saving

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var Cat = mongoose.model('Cat', { name: String });
var kitty = new Cat({ name: 'Zildjian' });
console.log(kitty);
kitty.save();
console.log(kitty);
this output:
{ name: 'Zildjian', _id: 523194d562b0455801000001 } twice
I've tried by delaying the save after a timeout, but it's the same, which points to the _id being set on the new Cat and not the .save()
Is this because of mongodb or mongoose, why is the _id set before the actual persistence?
Most MongoDb drivers will automatically generate the ObjectId/_id client side, including the native driver for Node.js. There's a tiny amount of locking that occurs to generate an ID uniquely, so there's little reason to not distribute the generation to connected clients.
Mongoose needs a unique identifier to track and reference objects, so it creates an identifier immediately.
In the Node.JS client you can optionally set for example the property forceServerObjectId to true to control this behavior.
However, this cannot be overridden when using Mongoose per the docs:
Mongoose forces the db option forceServerObjectId false and cannot be
overridden. Mongoose defaults the server auto_reconnect options to
true which can be overridden. See the node-mongodb-native driver
instance for options that it understands.

Mongoose models scheme in separate modul

Disclaimer:
I am new to mongoose/node, so please excuse me if I am misunderstanding some basic things.
Yes, I found already a few postings about this topic, but could not adapt it to my needs.
I structured my main-project into multiple separate projects. One separation is the "app-core" project, which will contain the core-models and -modules, to be injected by each other project (app-core is configured as dependency in the package.json file of each project).
A (simplified) model within the app-core currently looks like this:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var IndustrySchema = new Schema({
name: {
type: String,
required: true
}
});
module.exports = mongoose.model('Industry', IndustrySchema);
The wep-app includes this model as follow:
var Industry = require('app-core/models/Industry');
and creates the MongoDB connection like this:
var DB_URL = 'mongodb://localhost/hellowins';
var mongoose = require('mongoose');
var mongooseClient = mongoose.connect(DB_URL);
mongooseClient.connection.on('connected',function () {
console.log("MongoDB is connected");
});
Now I have the problem, that the model will not use the mongo connection that is defined in the app-web project, rather it will consider the connection configured in the app-core.
Due to encapsulation and responsibility design I definitly don't want the core to define the connections for each possible app (which may include the core-app).
So somehow I need to specify the the scheme only in the core.
I read already that I should not require the model itself (/app-core/models/Industry), and use the mongoose model instead
var Industry = mongoose.model("Industry");
But then I get the error
MissingSchemaError: Schema hasn't been registered for model "Test"
To fix this, I should register the models manually, like adviced in the first link (at the top of my posting). But somehow I don't like this approach, because I'd need to extend this everytime the application uses a new model.
And further I need a mongo connection even in the core-app - at least to run the mocha tests.
So I am bit confused about how to structure the architecture in this case.
UPDATE #1
I found now one working solution. But, unfortunately, this does not fit my requirements completely, because it is pretty difficult (resp. ugly) to extend a model by hooks (ie TestSchema.pre('save'..)).
Model (app-core)
exports.model = {
name: {
type: String,
required: true
}
};
models.js (app-web, executed once on startup)
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var models = ['Test']; // add many
exports.initialize = function() {
var l = models.length;
for (var i = 0; i < l; i++) {
var model = require('hw-core/models/' + models[i]);
var ModelSchema = new Schema(model.model);
module.exports = mongoose.model(models[i], ModelSchema);
}
};
app.js (web-app)
require('./conf/app_models.js').initialize();
Then I just can get a model as follow
var mongoose = require('mongoose');
var TestModel = mongoose.model("Test");
var Test = new TestModel();
Why don't you try to export the mongoose instance from your app-core module and use it later in the web-app to connect to a database
app-core index.js
var mongoose = require('mongoose');
module.exports = {
mongooseInstance: mongoose };
web-app index.js
var core = require('app-core'),
mongoose = core.mongooseInstance,
mongooseClient = mongoose.connect(DB_URL);
// and so on
This might work as long as you require your models in your controllers which are initialized after the code from the index.js. I hope my response is helpful.

property model of object mongoose is not a function

I'm using Mongoosejs, with MongoDB and Node.js.
I followed some online tutorials and created myself a test app as below, but keep getting the error message "propert model of object mongoose is not a function.
I dont understand what this means and why its erroring since i followed the online tutorials near enough the same.
Here is my code
// MongoDB test app. Getting to know MongoDB via MongooseJS
var mongoose = require ('mongoose'),
Schema = mongoose.Schema;
//Create Schema
var Storydb = new Schema ({
title: String,
body: String,
date: Date
});
mongoose.connect('mongodb://localhost/test');
//setup model and pass it schema
mongoose.model = ('Storydb',Storydb);
var StoryModel = mongoose.model ('Storydb');
var story = new StoryModel();
//Insert Data
story.title = 'The Man in the green shirt';
story.body = 'once upon a time, way back';
story.date = Date.now();
//save
story.save(function(err){
if (err) {throw err; }
console.log('saved story');
mongoose.disconnect();
});`
I've already tested my MongoDB connection. No issues there, and i am able to insert and retrieve data via the Mongo CLI.
I have also tested my Node.js configuration with basic Hello World examples, and no issues with configuration.
Instead of:
//setup model and pass it schema
mongoose.model = ('Storydb',Storydb);
you should do:
//setup model and pass it schema
mongoose.model('Storydb',Storydb);

Resources