"MissingSchemaError" when seeding database using mongoose-seeder - javascript

I am attempting to seed a database using mongoose-seeder, and I keep getting a MissingSchemaError. I am sure that I am setting up the schema properly, so I am lost as to why this is happening.
The file where I set up the schema looks like this:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
fullName: {
type: String,
required: true,
trim: true
},
emailAddress: {
type: String,
unique: true,
required: true,
match: /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)| .
(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-
Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
},
password: {
type: String,
required: true
}
});
const User = mongoose.model('User', UserSchema);
module.exports.User = User;
and in my main file:
'use strict';
// load modules
const morgan = require('morgan');
const mongoose = require('mongoose');
const seeder = require('mongoose-seeder');
const data = require('./data/data.json');
const express = require('express');
const app = express();
//set up database connection
mongoose.connect("mongodb://localhost:27017/courseapi");
const db = mongoose.connection;
//handle err connecting to db
db.on("error", (err) => console.error("Error connecting to database: ",
err));
//success
db.once("open", () => {
console.log("Connected to database");
seeder.seed(data, {dropDatabase: false}).then(function(dbData){
console.log("Database seeded!");
}).catch(function(err){
console.error("Error seeding database", err);
})
});
any help would be much appreciated!

The mongoose-seeder package is not maintained. Hence suggesting an alternative to import data. You can populate MongoDB in the CLI (command line interface) using mongoimport.It will load a JSON file into a specified MongoDB Instance & Collection. All you need is a mongod instance to be running before execution.
Please go through the walkthrough.

thank you for your help! The project required using a module to seed the data, so I ended up using mongoose-seed instead. (Required some reformatting of the json, but thankfully the file was relatively small)

it's better to use the actively maintained Seedgoose. It's the ultimate mongoose seeder with smart reference support.

Related

Mongoose not saving data according to a function (discord.js)

Today, I decided to make a Discord RPG bot which of course requires profile stats such as coins and the actual users. Therefore, I searched up a tutorial on how I can do this with MongoDB but I am running into one issue. When a guild member joins and the bot is running, the data does not save with no error at all and I am unsure of why this is happening. I have tried troubleshooting the connection status by adding a line console.log(mongoose.connection.readyState) after the bot attempts to connect to the database. This returns 1 which means the connection is fine. I cannot find any other reason why this is caused so I decided to ask a question after hours of thinking.
(index.js): Connecting to the database
const mongoose = require("mongoose");
mongoose.connect(process.env.MONGO_SERVER, {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => [
console.log("Connected to MongoDB Database successfully!"),
console.log(mongoose.connection.readyState)
]).catch((err) => {
console.error(err);
});
(profileSchema.js): Creating a profile schema
const mongoose = require("mongoose");
const profileSchema = new mongoose.Schema({
id: { type: String, require: true, unique: true },
serverid: { type: String, require: true },
coins: { type: Number, default: 0 },
bank: { type: Number }
});
const model = mongoose.model("ProfileModels", profileSchema);
module.exports = model;
(guildMemberAdd.js): Creating and uploading the data into the database
const profileModel = require('../models/profileSchema');
module.exports = async(client, discord, member) => {
let profile = await profileModel.create({
id: member.id,
serverid: member.guild.id,
coins: 0,
bank: 0
})
profile.save();
}
The reason is to do with the way you connect to mongo
BY default mongo closes the connection after connecting to a database. To do this, when connecting to mongo pass in the keepAlive option, so it would look something like:
mongoose.connect(process.env.MONGO_SERVER, {
useNewUrlParser: true,
useUnifiedTopology: true,
keepAlive: true
})
This will then mean an active connection to your database will be kept open
You are exporting 'model' from profileSchema.js and requiring 'profileModel ' from guildMemberAdd.js?
so import model from profileSchema and not profileModel
Fix: Make sure the guildMemberAdd event is being called by adding console.log statements.
If not, check if guildMemberAdd's code is different to other event codes.

mongoose is not creating db using mongoose.connect

I'm trying to create new database using mongoose.connect('mongodb://localhost:27017/imagesDB'); But is not creating. And please don't answer me saying that I need to add entries to it. I did it. Here's my full code.
const express = require("express");
const mongoose = require('mongoose');
const app = express();
mongoose.connect('mongodb://localhost:27017/imagesDB').then(() => {
console.log("Connected to Database");
}).catch((err) => {
console.log("Not Connected to Database ERROR! ", err);
});
const imageSchema = new mongoose.Schema ({
name: String,
category: String,
author: String,
tag: String,
imageURL: String
});
const Image = mongoose.model("Image", imageSchema);
const image = new Image({
name: "Cat",
category: "Animal",
author:"Cat",
tag: "Animals",
imageURL: "https://cdn-media-2.freecodecamp.org/w1280/5f9c9a5d740569d1a4ca2531.jpg"
});
image.save();
app.get("/", function(req, res){
res.send("Everything is running properly!");
});
app.listen(3000, function(){
console.log("Server succesfully started on port 3000!");
});
Can you guys please test it for yourself? Does this creates a new database called imagesDB???
For me no, It is not working. I opened new tab in terminal and commanded mongo so it opened mongo client where i typed show dbs but it is not showing except these three admin, config and local.
I also wanna make it clear that mongo service is running, I did it by commanding mongod --ipv6 in terminal.
The problem is solved by changing localhost to 127.0.0.1 .
Here's how it looks
mongoose.connect('mongodb://127.0.0.1:27017/imagesDB').then(() => {
console.log("Connected to Database");
}).catch((err) => {
console.log("Not Connected to Database ERROR! ", err);
});
Are you using Mongoose Compass or Atlas?
Secondly, try doing it on VSCode terminal it will work then
You have to created your database named "imagesDB" in MongoDB Compass, or other GUI tool.

Sequelize with asynchronous configuration in nodejs

I have been bashing my head for days as I cannot find a valid example of async configuration in Sequelize
So as you may know, you can simply config a Sequelize instance like that
const sequelize = new Sequelize('postgres://user:pass#example.com:5432/dbname')
and then declare your Model
const User = sequelize.define('User', {
// Model attributes are defined here
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING
// allowNull defaults to true
}
}, {
// Other model options go here
});
However what happens when the db credentials comes from an external service?
const credentials = await getDbCredentials();
const sequelize = new Sequelize({credentials})
since sequelize models creation are coupled with the instance creation (unlike many others ORMs) this becomes a big problem.
My current solution is the following:
const Sequelize = require("sequelize");
// Models
const { User } = require("./User");
const env = process.env.NODE_ENV || "development";
const db = {};
let sequelize = null;
const initSequelize = async () => {
if (!sequelize) {
let configWithCredentials = {};
if (env === "production") {
const credentials = await getDbCredentials();
const { password, username, dbname, engine, host, port } = credentials;
configWithCredentials = {
username,
password,
database: dbname,
host,
port,
dialect: engine,
operatorsAliases: 0
};
}
const config = {
development: {
// Dev config
},
production: configWithCredentials,
};
sequelize = new Sequelize(config[env]);
sequelize.authenticate().then(() => {
console.log("db authenticated")
});
});
}
db.User = User;
db.sequelize = sequelize;
db.Sequelize = Sequelize;
};
initSequelize().then(() => {
console.log("done");
});
module.exports = db;
However I feel that this is not a good approach because of the asynchronous nature of the initialization and sometimes the db is undefined.
Is there a better way to approach this thing?
Thanks
You can achieve this with beforeConnect hook, something like this:
sequelize = new Sequelize(config.database, '', '', config);
sequelize.beforeConnect(async (config) => {
config.username = await getSecretUsername();
config.password = await getSecretPassword();
});
Leave the initial credentials empty, then use beforeConnect to mutate the config. Not sure if this is the cleanest way to use it but seems to be working.
https://sequelize.org/master/manual/hooks.html
I think your db is sometimes undefined, because in your async function you're not "waiting" for the resolution of sequelize.authenticate(). Change this:
sequelize.authenticate().then(() => {
console.log("db authenticated")
});
To this:
await sequelize.authenticate()
console.log("db authenticated")
What was happening, is that your initSequelize async function would resolve, before sequelize.authenticate promise would. This is a common pitfall in JS. I think this adjustment will solve your problem. Regarding "the best approach", i don't see much that can be done here, but of course i don't have the entire picture.
I found a 'pure' sequelize way to do this through lifecycle hooks:
Basically a generic setup in a db.js file would look like this:
const { Sequelize } = require('sequelize');
const asyncFetch = require('../util/async-fetch');
const sequelize = new Sequelize({
dialect: 'mysql',
database: 'db_name',
host: '127.0.0.1'
});
sequelize.beforeConnect(async (config) => {
const [username, password] = await Promise.all([
asyncFetch('username'),
asyncFetch('password')
]);
config.username = username;
config.password = password;
});
module.exports = sequelize;
The sequelize model definition is really just a plain object so that can be set early. Model initialisation does require a sequelize instance to be passed in.
The setup was a bit clearer to me when using ES6 class definitions for the models. sequelize.define is replaced with a call to Model.init, and this can all be done in an async setup function.
const Sequelize = require('sequelize')
const { Model } = Sequelize
class User extends Model {
static get modelFields(){
return {
id: {
type: Sequelize.UUID,
primaryKey: true,
defaultValue: Sequelize.UUIDV4,
},
name: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
}
}
}
static get modelOptions(){
return {
version: true,
}
}
static init(sequelize){
const options = { ...this.modelOptions, sequelize }
return super.init(this.modelFields, options)
}
static associate(models) {
this.hasMany(models.Task)
}
}
module.exports = User
const User = require('./User')
class Database {
async static setup(){
const credentials = await getCredentials()
this.sequelize = new Sequelize(credentials)
User.init(this.sequelize)
this.User = User
// When you have multiple models to associate add:
this.User.associate(this)
}
}
module.exports = Database
Due to the async credentials requirement, the rest of your app will just need to cope with the delay until the DB is setup. If this is a koa/express app for example, you could delay the server .listen() until the Database.setup() promise has resolved.
As this would have changed a lot of my code. I have ended up by creating a script in golang that gets my credential "asynchronously" before running my server.
I have use some code from this package: https://github.com/telia-oss/aws-env
And then pass my starting script as a command argument so I could "inherit" the environmental variables
./getEnv exec -- node index.js

Moongose, expressjs and node-webkit

I'm building an app using node-webkit, based on expressjs and mongoose. I'm new to basically all of this.
I've got a mongoDb hosted online and i'm try to use it in my app, but i'm missing something
I created in model folder db.js, where i connect with the db
var mongoose = require('mongoose');
mongoose.connect('mongodb://user:password#ds012345.mlab.com:port/mydb') //this isn't the real link
then my model, clients.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var clientSchema = new Schema ({
name: String,
//other fields
});
var client = mongoose.model('client', clientSchema);
module.exports = client;
Then, in my app.js
var db = require('./model/db')
I'm also using routes, so in my index.js i got
var client = require('../model/clients')
But i cannot use any function (save, find, ecc.), i can just create models.
I think I'm not connecting in the right way all the modules, i was previously using diskdb and i connected to it in my index.js, but i tried in the same way and it doesn't work anyway.
Also, when i build the app, my mongoose connection status is 2.
Here are a few things:
what is ecc? you should connect to something like this: mongoose.connect('mongodb://localhost:27017/test');
27017 is the default port for MongoDB and test is the name of your database. Also make sure you start mongo server with mongod then run mongo console mongo.
Your field should specify type of the data:
var clientSchema = new Schema ({
name: String,
age: Number
});
So you want to save the document into database:
var client = mongoose.model('client', clientSchema);
var data = {
nome: 'something'
};
var user = new client(data);
user.save(function(err) {
if(err) console.log(err);
});
In your route, you can do something like this to query back and send data back to the req:
var express = require('express');
var router = express.Router();
var clientSchema = require('../models/clientSchema');
router.get('/', function(req, res, next) {
UserSchema.find({} , function(err, data) {
if (err) console.log(err);
res.render('index', {
data: data
});
});
});
module.exports = router;
Hope this help!

Mongoose and multiple database in single node.js project

I'm doing a Node.js project that contains sub projects. One sub project will have one Mongodb database and Mongoose will be use for wrapping and querying db. But the problem is
Mongoose doesn't allow to use multiple databases in single mongoose instance as the models are build on one connection.
To use multiple mongoose instances, Node.js doesn't allow multiple module instances as it has caching system in require(). I know disable module caching in Node.js but I think it is not the good solution as it is only need for mongoose.
I've tried to use createConnection() and openSet() in mongoose, but it was not the solution.
I've tried to deep copy the mongoose instance (http://blog.imaginea.com/deep-copy-in-javascript/) to pass new mongoose instances to the sub project, but it throwing RangeError: Maximum call stack size exceeded.
I want to know is there anyways to use multiple database with mongoose or any workaround for this problem? Because I think mongoose is quite easy and fast. Or any other modules as recommendations?
According to the fine manual, createConnection() can be used to connect to multiple databases.
However, you need to create separate models for each connection/database:
var conn = mongoose.createConnection('mongodb://localhost/testA');
var conn2 = mongoose.createConnection('mongodb://localhost/testB');
// stored in 'testA' database
var ModelA = conn.model('Model', new mongoose.Schema({
title : { type : String, default : 'model in testA database' }
}));
// stored in 'testB' database
var ModelB = conn2.model('Model', new mongoose.Schema({
title : { type : String, default : 'model in testB database' }
}));
I'm pretty sure that you can share the schema between them, but you have to check to make sure.
Pretty late but this might help someone. The current answers assumes you are using the same file for your connections and models.
In real life, there is a high chance that you are splitting your models into different files. You can use something like this in your main file:
mongoose.connect('mongodb://localhost/default');
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', () => {
console.log('connected');
});
which is just how it is described in the docs. And then in your model files, do something like the following:
import mongoose, { Schema } from 'mongoose';
const userInfoSchema = new Schema({
createdAt: {
type: Date,
required: true,
default: new Date(),
},
// ...other fields
});
const myDB = mongoose.connection.useDb('myDB');
const UserInfo = myDB.model('userInfo', userInfoSchema);
export default UserInfo;
Where myDB is your database name.
One thing you can do is, you might have subfolders for each projects. So, install mongoose in that subfolders and require() mongoose from own folders in each sub applications. Not from the project root or from global. So one sub project, one mongoose installation and one mongoose instance.
-app_root/
--foo_app/
---db_access.js
---foo_db_connect.js
---node_modules/
----mongoose/
--bar_app/
---db_access.js
---bar_db_connect.js
---node_modules/
----mongoose/
In foo_db_connect.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/foo_db');
module.exports = exports = mongoose;
In bar_db_connect.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/bar_db');
module.exports = exports = mongoose;
In db_access.js files
var mongoose = require("./foo_db_connect.js"); // bar_db_connect.js for bar app
Now, you can access multiple databases with mongoose.
As an alternative approach, Mongoose does export a constructor for a new instance on the default instance. So something like this is possible.
var Mongoose = require('mongoose').Mongoose;
var instance1 = new Mongoose();
instance1.connect('foo');
var instance2 = new Mongoose();
instance2.connect('bar');
This is very useful when working with separate data sources, and also when you want to have a separate database context for each user or request. You will need to be careful, as it is possible to create a LOT of connections when doing this. Make sure to call disconnect() when instances are not needed, and also to limit the pool size created by each instance.
Mongoose and multiple database in single node.js project
use useDb to solve this issue
example
//product databse
const myDB = mongoose.connection.useDb('product');
module.exports = myDB.model("Snack", snackSchema);
//user databse
const myDB = mongoose.connection.useDb('user');
module.exports = myDB.model("User", userSchema);
A bit optimized(for me atleast) solution. write this to a file db.js and require this to wherever required and call it with a function call and you are good to go.
const MongoClient = require('mongodb').MongoClient;
async function getConnections(url,db){
return new Promise((resolve,reject)=>{
MongoClient.connect(url, { useUnifiedTopology: true },function(err, client) {
if(err) { console.error(err)
resolve(false);
}
else{
resolve(client.db(db));
}
})
});
}
module.exports = async function(){
let dbs = [];
dbs['db1'] = await getConnections('mongodb://localhost:27017/','db1');
dbs['db2'] = await getConnections('mongodb://localhost:27017/','db2');
return dbs;
};
I have been using this method and it works great for me until now.
const mongoose = require('mongoose');
function makeNewConnection(uri) {
const db = mongoose.createConnection(uri, {
useNewUrlParser: true,
useUnifiedTopology: true
});
db.on('error', function (error) {
console.log(`MongoDB :: connection ${this.name} ${JSON.stringify(error)}`);
db.close().catch(() => console.log(`MongoDB :: failed to close connection ${this.name}`));
});
db.on('connected', function () {
mongoose.set('debug', function (col, method, query, doc) {
console.log(`MongoDB :: ${this.conn.name} ${col}.${method}(${JSON.stringify(query)},${JSON.stringify(doc)})`);
});
console.log(`MongoDB :: connected ${this.name}`);
});
db.on('disconnected', function () {
console.log(`MongoDB :: disconnected ${this.name}`);
});
return db;
}
// Use
const db1 = makeNewConnection(MONGO_URI_DB1);
const db2 = makeNewConnection(MONGO_URI_DB2);
module.exports = {
db1,
db2
}

Categories