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.
Related
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 }
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
I'm new to CompoundJS. I'm working on a sample app. If following the below tutorial:
Using Mongoose Models
I have written the below code in db/schema.js file:
customSchema(function () {
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_database');
var Schema = mongoose.Schema, ObjectId = Schema.ObjectId;
module.exports["mongoose"] = mongoose;
module.exports["model"] = {}
});
In my model.js file (person.js), I have the code below:
var Person = mongoose.model('Person', new module.schema());
model['Person'] = Person;
When I run compound s , I'm getting ReferenceError: mongoose is not defined.
Any help would be appreciable. Thanks in advance.
Wiki is outdated, all documentation currently available at http://compoundjs.com, and i will remove wiki to avoid confusions.
You can use this example if you need mongoose as ORM: https://github.com/anatoliychakkaev/mongoose-compound-example-app
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.
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);