I am trying to integrate mongoose and apollo with Next.js
I wrote this wrapper around apollo server:
import mongoose from "mongoose"
const {logger} = require("../middleware/logger");
const connect = async () => {
logger.info("Connecting to DB...");
await mongoose
.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useFindAndModify: false,
useUnifiedTopology: true
}).then(() => logger.info(`Mongo running at ${process.env.MONGO_URI}`))
.catch(err => logger.error(err));
}
const connectDB = (handler) => async (req, res) => {
if (mongoose.connections[0].readyState !== 1) {
await connect();
}
return handler(req, res);
}
const db = mongoose.connection;
db.once('ready', () => logger.info(`Connected to mongo on ${process.env.MONGO_URI}`));
export default connectDB;
In this model in separate file:
const mongoose = require('mongoose');
const {Schema} = mongoose;
const CustomerSchema = new Schema({
name: {
type: String,
required: [true, 'Customer name is required'],
unique: true,
trim: true,
},
createdAt: {
type: Date,
default: Date.now
}
}, {
toJSON: {
transform: function (doc, ret) {
ret._id = ret._id.toString();
delete ret.__v
}
}
});
module.exports = mongoose.model('Customer', CustomerSchema);
My apollo server looks like this now:
import {ApolloServer, gql} from "apollo-server-micro";
import connectDB from "../../middleware/db-middleware";
const _Customer = require("../../db/models/Customer");
const typeDefs = gql`
type Customer {
id: ID!
name: String!
createdAt: String
}
type Query {
hello: String!
}
type NewCustomerResponse {
success: Boolean!
message: String
}
type Mutation {
addCustomer(name: String!): NewCustomerResponse!
}
`;
const resolvers = {
Mutation: {
addCustomer: async (parent, {name}, context, info) => {
await _Customer.create({name});
return {success: true, message: "Sample message"};
}
}
};
const apolloServer = new ApolloServer({
typeDefs,
resolvers,
context: () => ({}),
});
export default connectDB(apolloServer.createHandler({path: "/api/gql"}));
First run works ok, but when I modify anything, and next.js auto-recompiles source files, it throws this error:
OverwriteModelError: Cannot overwrite `Customer` model once compiled.
Does anyone knows what am I doing wrong and how to resolve this issue?
Related
Here I created a project to store employee information, in this project DB also successfully connected, but when I tried to retrieve or create a new record, it shows error like this,
I already changed the mongo network setting also,
MongooseError: Operation users.insertOne() buffering timed out after 10000ms
at Timeout.
server.js
const express = require("express");
const mongoose = require("mongoose");
const Router = require("./routes");
const cors = require('cors');
const { error } = require("jquery");
const app = express();
app.use(express.json());
mongoose.set('strictQuery', false);
mongoose.connect('mongodb+srv://admin:admin1234#hhap-db.n8zxs62.mongodb.net/test',
{ useNewUrlParser: true, useFindAndModify: true, useUnifiedTopology: true },
function CheckDb(){
if(error){
console.log("Error");
}
else{
console.log("DB Connected");
}
}
);
app.use(Router);
app.use(cors());
app.listen(3000, () => {
console.log("Server is running at port 3000");
});
router.js
const express = require("express");
const userModel = require("./model/userModel");
const app = express();
app.post("/user/create", async (request, response) => {
const user = new userModel(request.body);
try {
await user.save();
response.send(user);
} catch (error) {
response.status(500).send(error);
console.log(error);
}
});
app.get("/user/getAll", async (request,response) => {
const user = await userModel.find({});
console.log(user);
try {
response.send(user);
} catch (error) {
response.status(500).send(error);
console.log(error);
}
});
module.exports = app;
userModel.js
const mongoose = require("mongoose");
const user = new mongoose.Schema({
fName: { type: String, required: true, },
lName: { type: String, required: true, },
address: { type: String, required: false, },
email: { type: String, required: true, },
mobileNumber: { type: Number, default: 0, },
password: { type: String, required: true, },
isActive: { type: Boolean, required: true, },
userType: { type: String, required: true, },
});
const User = mongoose.model("user", user);
module.exports = User;
Issue in mongoose.connect
Try this:
mongoose
.connect("mongodb+srv://admin:admin1234#hhap-db.n8zxs62.mongodb.net/test", {
useNewUrlParser: true,
useFindAndModify: false,
useUnifiedTopology: true,
useCreateIndex: true,
keepAlive: true
})
.then(
async() => {
console.log("database connected")
},
(err) => {
console.log(err, "Error")
}
)
Newbie in Node js, I am using Node JS to build APIs and using class. There are 2 routes till now, one is to fetch all users which is working fine, another is to insert new user which is not working. It is returning {} with status 500.
Here are the files.
index.js
import server from "./config/server.js";
import './config/database.js';
const PORT = process.env.PORT || 5000;
server.listen(PORT, () => {
console.log(`app running on port ${PORT}`);
});
config/database.js
import mongoose from "mongoose";
class Connection {
constructor() {
const url =
process.env.MONGODB_URI || `mongodb://localhost:27017/dev-muscles`;
console.log("Establish new connection with url", url);
mongoose.Promise = global.Promise;
// mongoose.set("useNewUrlParser", true);
// mongoose.set("useFindAndModify", false);
// mongoose.set("useCreateIndex", true);
// mongoose.set("useUnifiedTopology", true);
mongoose.connect(url);
}
}
export default new Connection();
config/server.js
import express from "express";
import UserController from "../src/models/controllers/UserController.js";
const server = express();
server.use(express.json());
server.get(`/users`, UserController.getAll);
server.post(`/users/create`, UserController.create);
export default server;
src/models/User.js
import mongoose from "mongoose";
const { Schema } = mongoose;
import validator from "validator";
class User {
initSchema() {
const schema = new Schema({
first_name: {
type: String,
required: true,
trim: true
},
last_name: {
type: String,
required: true,
trim: true
},
email: {
type: String,
required: true,
trim: true,
lowercase: true,
// validate(value) {
// if( !validator.isEmail(value) ) {
// throw new Error('Email is invalid')
// }
// }
},
phone: {
type: Number,
required: true,
trim: true
},
password: {
type: String,
required: true
}
});
// schema.plugin(validator);
mongoose.model("users", schema);
}
getInstance() {
this.initSchema();
return mongoose.model("users");
}
}
export default User;
src/controllers/UserController.js
import Controller from "./Controller.js";
import User from ".././models/User.js";
const userModelInstance = new User().getInstance();
class UserController extends Controller {
constructor(model) {
super(model);
}
}
export default new UserController(userModelInstance);
src/controllers/Controller.js
class Controller {
constructor(model) {
this.model = model;
this.getAll = this.getAll.bind(this);
this.create = this.create.bind(this);
}
async getAll(req, res) { // works fine
return res.status(200).send(await this.model.find({}));
}
async create(req, res) { // this is returning {} with status code 500
try {
// return res.send(req.body);
return res.status(201).send(await new this.model.save(req.body));
} catch (error) {
res.status(500).send(error);
}
}
}
export default Controller;
Refactor the create method like so.
const ItemToSave = new this.model(req.body);
const savedItem = await ItemToSave.save();
return res.status(201).send(savedItem);
I have a mongoose schema-WishlistItem, which has a validation: A new WishlistItem cannot be created if it's wishlist property(an object id) doesn't belong to a real existing Wishlist in the database. The WishlistItem has this validation so that wishlistItems without parent wishlists aren't accidentally added to the database.
How can I run tests on the WishlistItem model without creating a real wishlist?
I'm using mocha and chai.
The test to create a wishlistItem
Currently the test gives:
AssertionError: expected undefined to be an object.
This is because await WishlistItem.create({... throws an error:
ValidationError: WishlistItem validation failed: wishlist: Invalid WishlistItem "wishlist" property. No wishlist found with id: 5f9480a69c4fcdc78d55397d since we don't have that wishlist in the database.
const chai = require('chai');
const mongoose = require('mongoose');
const { expect } = chai;
const dbConnect = async (dsn) =>
mongoose.connect(dsn, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
});
const should = chai.should();
const WishlistItem = require('../testsFiles/WishlistItem.Model');
describe('Wishlist Item', () => {
before(async () => {
dbConnect(`mongodb://127.0.0.1:27017/schemaDepTest`);
});
context('create wishlist item', () => {
it('should create a wishlist item with valid arguments', async function () {
let wishlist;
try {
wishlist = await WishlistItem.create({
itemName: 'Purse',
price: '5.00',
wishlist: mongoose.Types.ObjectId('5f9480a69c4fcdc78d55397d'),
});
} catch (err) {
console.log(err);
}
expect(wishlist).to.be.an('Object');
});
});
});
WishlistItem Schema
const mongoose = require('mongoose');
const itemSchema = new mongoose.Schema(
{
itemName: { type: String, required: true, trim: true },
price: { type: String, required: true, trim: true },
wishlist: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Wishlist',
required: true,
},
},
{ timestamps: { createdAt: 'created_at' } }
);
itemSchema.path('wishlist').validate(async function (value) {
const WishlistModel = require('./Wishlist.Model');
const wishlist = await WishlistModel.findOne({ _id: value });
if (!wishlist) {
throw new Error(
`Invalid WishlistItem "wishlist" property. No wishlist found with id: ${value}`
);
} else {
return true;
}
}, 'Parent Wishlist non existent');
const WishlistItem = mongoose.model('WishlistItem', itemSchema);
module.exports = WishlistItem;
The Wishlist Schema
const mongoose = require('mongoose');
const wishlistSchema = new mongoose.Schema(
{
wishlistName: {
type: String,
required: true,
trim: true,
},
wishlistItems: [
// reference, one-to-many
{
type: mongoose.Schema.Types.ObjectId,
ref: 'WishlistItems',
},
],
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true,
},
},
{ timestamps: { createdAt: 'created_at' } }
);
const Wishlist = mongoose.model('Wishlist', wishlistSchema);
module.exports = Wishlist;
This post answered my question
I just had to add
sinon.stub(Object.getPrototypeOf(Wishlist), 'findOne').callsFake(() => 'mock');
This way, when WishlistItem tries to validate that the Wishlist exist by calling Wishlist.findOne, () => 'mock' is called in place of findOne.
full test code:
const sinon = require('sinon');
const chai = require('chai');
const mongoose = require('mongoose');
const { expect } = chai;
const dbConnect = async (dsn) =>
mongoose.connect(dsn, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
});
const should = chai.should();
const WishlistItem = require('../testsFiles/WishlistItem.Model');
const Wishlist = require('../testsFiles/Wishlist.Model');
describe('Wishlist Item: testing dependency mocking ', () => {
before(async () => {
dbConnect(`mongodb://127.0.0.1:27017/schemaDepTest`);
});
context('create wishlist item', () => {
it('should create a wishlist item with valid arguments', async function () {
sinon.stub(Object.getPrototypeOf(Wishlist), 'findOne').callsFake(() => 'mock');
let wishlist;
try {
wishlist = await WishlistItem.create({
itemName: 'Purse',
price: '5.00',
wishlist: mongoose.Types.ObjectId('5f9480a69c4fcdc78d55397d'),
});
} catch (err) {
console.log(err);
}
console.log(wishlist);
expect(wishlist).to.be.an('Object');
});
});
});
I'm facing this problem since couple of days where I'm trying to insert the data into mongodb using mongoose but not able to get the data in mongodb. Below is the schema that I have created
const mongoose = require('mongoose')
const db = require('../db/db')
const crypto = require('crypto')
const { v4 : uuidv4 } = require('uuid');
const validator = require('validator')
// const { stringify } = require('querystring')
const schema = mongoose.Schema
const userSchema = new schema({
ObjId: schema.Types.ObjectId,
name : {
type : String,
trim: true,
required : true,
maxlength: 32
},
email : {
type : String,
trim: true,
required : true,
validate(value) {
if(!validator.isEmail(value)){
throw new Error ('The Email you have entered is not correct. Please enter the correct Email ID')
}
}
},
hashed_password : {
type : String,
required : true,
},
about : {
type : String,
trim: true,
required: true
},
salt : String,
user_roles: {
type: Number,
default: 0,
required: true
},
history : {
type: Array,
default: []
},
// timestamps: {
// createdAt : '',
// updatedAt : {type : Date, default : Date.now()},
// },
}, {timestamps: true})
// added virtual field
userSchema.virtual('password')
.set((password) =>{
this.password = password,
this.salt = uuidv4()
this.hashed_password = this.encryptPassword(password)
})
.get(() => {
return this._password
})
userSchema.methods = {
encryptPassword : (password) => {
if(!password) return ''
try {
return crypto.createHmac('sha256', this.salt)
.update(password)
.digest("hex")
}
catch(error) {
if(error) {
console.log('Found an Error in Line 70 in User.Js', error.message)
}
}
}
}
module.exports = mongoose.model("User", userSchema);
This is how I'm connecting the db
const mongoose = require('mongoose')
require('dotenv').config
// const connectionURL = 'mongodb://127.0.0.1:27017'
//const databaseName = 'ecommerce_db'
mongoose.connect(
// connectionURL,
process.env.MONGOURI,
{
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
}
)
// .then((result) => { console.log('Mongo DataBase Connected', result)})
.then(() => { console.log('Mongo DataBase Connected')})
.catch((err) => {console.log('Mongoose Connection Failed', err)})
and this is where I'm saving the data
const User = require('../models/user')
const { response } = require('express')
const mongoose = require('mongoose')
exports.signUp = (req, res) => {
console.log('[Logging]', req.body)
// const user = new User({
// _id: mongoose.Schema.Types.ObjectId(),
// name: req.body.name,
// email: req.body.email,
// password: req.body.hashed_password
// })
const user = new User(req.body)
user.save((error, response) => {
if(error) {
return res.status(400).json({
error
})
}
res.json({
user
})
})
}
I'm getting all the correct input and success messages but still I'm not able to get the data inside mongodb, am I doing something wrong
I am using mongoose to handle my schemas, with MongoDB, but when trying to save a new entry to a collection the save() method appears to be stuck, neither the then() method or the catch() method of the promise appear to be called.
Does anyone have any ideas?
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// const Promise = require('bluebird');
const config = require('./config');
const UserSchema = new Schema({
email: { type: String, required: true, index: { unique: true } },
name: { type: String, required: false },
password: { type: String, required: true }
});
const User = mongoose.model('User', UserSchema);
console.log('config.database.url', config.database.url);
mongoose.Promise = global.Promise;
return mongoose.createConnection(config.database.url, {
useMongoClient: true
})
.then((connection) => {
const user = new User({
email: 'someuser#somedomain.com',
password: 'xxxxx'
});
const prom = user.save();
// Displays: 'promise: Promise { <pending> }'
console.log('promise:', prom);
return prom
.then((result) => {
// Don't see this output
console.log('result:', result);
})
.catch((error) => {
// Don't see this output either
console.log('error:', error);
});
})
.catch((error) => {
console.log(error);
});
Environment: nodejs 8.9.0, node modules: Mongoose 4.13.6, mongodb 2.2.33
A little more experimenting and it would appear that I need to ensure the model is tied to the connection, such that:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// const Promise = require('bluebird');
const config = require('./config');
const UserSchema = new Schema({
email: { type: String, required: true, index: { unique: true } },
name: { type: String, required: false },
password: { type: String, required: true }
});
let User;
console.log('config.database.url', config.database.url);
mongoose.Promise = global.Promise;
return mongoose.createConnection(config.database.url, {
useMongoClient: true
})
.then((connection) => {
// associate model with connection
User = connection.model('User', UserSchema);
const user = new User({
email: 'someuser#somedomain.com',
password: 'xxxxx'
});
const prom = user.save();
// Displays: 'promise: Promise { <pending> }'
console.log('promise:', prom);
return prom
.then((result) => {
// Don't see this output
console.log('result:', result);
})
.catch((error) => {
// Don't see this output either
console.log('error:', error);
});
})
.catch((error) => {
console.log(error);
});
Alternatively we should use the connect() method that will work with the model associated via mongoose.model.
For createConnection() can be used to create multiple connections, so using a 'global' model is not supported, from what I can tell.
Saying all this it would be nice if save() didn't simply block.
Note: In researching a refinement to my answer I came across the following: Queries hang when using mongoose.createConnection() vs mongoose.connect()