Mongoose is not creating a collection on save() function - javascript

I have below schema.
const mongoose = require('mongoose');
const JobSchema = new mongoose.Schema({
posterId: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
location: {
type: String,
required: true,
},
}, { timestamp: true });
module.exports = mongoose.model('Job', JobSchema);
And I use below code to save new data to this collection.
const Job = require('../../models/Job');
new Job({
posterId,
title,
location,
})
.save()
.then(job => {
console.log('JOB: ', job) // consoles the newly added job to collection.
if (job) {
response.json({
message: 'Job is saved successfully.',
});
} else {
response.json({
message: 'Job can not be saved at this time. Please try again later.',
});
}
})
.catch(error => {
response.json(error);
});
The above code successfully saves new information to job collection but when I check that in mongoDB using mongodb CLI. I do not see any job collection there so it is not creating the collection. What am I doing wrong and how can I fix this?

Related

Mongoose v6.2.7 new Model.save() method not working tried promise, callback and async await in try-catch nothing works

Initially, the project was set up with promise support, and all queries used promise like method.then().catch() later some were converted to try-catch with async await. All worked fine until a few weeks ago when all of a sudden some methods stopped working, I have tried converting the methods to many different variations from promise to callback and to try-catch. await new Model(object).save() does not save the record. I am using mongoose.createConnection because I need to connect to two databases.
Here is how I init my DB
const mongoose = require("mongoose");
mongoose.Promise = require('bluebird');
function makeNewConnection(uri, id) {
const db = mongoose.createConnection(uri);
db.on("error", function(error) {
console.log(
`MongoDB :: connection ${this.name} :: ${id} ${JSON.stringify(error)}`
);
db.close().catch(() =>
console.log(`MongoDB :: failed to close connection ${this.name}`)
);
});
db.on("connected", async function() {
mongoose.set("debug", function(col, method, query, doc) {
console.log(
`MongoDB :: ${
this.conn.name
} :: ${id} ${col}.${method}(${JSON.stringify(query)},${JSON.stringify(
doc
)})`
);
});
console.log(`MongoDB :: connected ${this.name} :: ${id}`);
require("../models/notification.model");
if (process.env.DATABASE_ENV === "local" && id === "cloud") {
require("../helpers/data.sync.helper");
}
});
db.on("disconnected", function() {
console.log(`MongoDB :: disconnected ${this.name} :: ${id}`);
});
return db;
}
// Use
let local, cloud;
if (process.env?.DATABASE_ENV === "local") {
// Connect to local database
local = makeNewConnection(
`mongodb://${process.env.DATABASE_USER}:${process.env.DATABASE_PASS}#127.0.0.1:27017/Eyemasters?retryWrites=true&authSource=admin&useNewUrlParser=true&useUnifiedTopology=true&w=majority`,
"local"
);
// Connect to cloud database
cloud = makeNewConnection(
`mongodb://${process.env.DATABASE_USER}:${process.env.DATABASE_PASS}#64.227.44.132:27017/Eyemasters?retryWrites=true&w=majority`,
"cloud"
);
// Start Database sync helper
} else {
// Connect to cloud local database
local = makeNewConnection(
`mongodb://${process.env.DATABASE_USER}:${process.env.DATABASE_PASS}#localhost:27017/Eyemasters?retryWrites=true&w=majority`,
"local"
);
}
module.exports = {
local,
cloud
};
And here is one of my models having the issue.
const mongoose = require("mongoose");
mongoose.Promise = require('bluebird');
const { local, cloud } = require("../config/database.config");
const { genId } = require("../helpers/doc.id.generator");
const validator = require("validator");
const UserSchema = mongoose.Schema(
{
_id: mongoose.Schema.Types.ObjectId,
email: {
type: String,
required: true,
unique: true,
validate: {
validator: validator.isEmail,
message: "{VALUE} is not a valid email",
isAsync: false
}
},
hash: { type: String, bcrypt: true, rounds: 10 },
firstname: { type: String, required: true },
lastname: { type: String, required: true },
phone: { type: String },
dateOfBirth: { type: Date },
designation: { type: String },
role: { type: mongoose.Schema.Types.ObjectId, ref: "Role" },
passport: { type: String },
accountDetails: {
name: String,
number: Number,
bank: String
},
defaultBranch: {
type: mongoose.Schema.Types.ObjectId,
ref: "Branch"
},
branches: [{ type: mongoose.Schema.Types.ObjectId, ref: "Branch" }],
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
lastModifiedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
webpush: { type: Object },
inactive: { type: Boolean, default: true },
approved: { type: Boolean, default: false },
activationCode: { type: String, unique: true },
activationExpiresIn: { type: Date }
},
{ toJSON: { virtuals: true }, timestamps: true }
);
UserSchema.plugin(require("mongoose-bcrypt"));
genId(UserSchema);
UserSchema.pre("save", function(next) {
if (!this.createdBy) this.createdBy = this._id;
if (!this.lastModifiedBy) this.lastModifiedBy = this._id;
});
exports.User = exports.User || local.model("User", UserSchema);
exports.OnlineUser = exports.OnlineUser || cloud.model("User", UserSchema);
And Lastly my controller setup;
exports.create = async (req, res) => {
// Validating entered data
if (
!req.body.firstname ||
!req.body.lastname ||
req.body.firstname.length < 3 ||
req.body.lastname.length < 3 ||
!req.body.email ||
!req.body.role ||
req.body.email.length < 3
) {
return res.status(400).send({
message: "Please fill in all required fields"
});
}
try {
const user = await User.findOne({
email: req.body.email.toLowerCase()
});
if (user) {
throw new Error("User with email " + req.body.email + " already exist");
}
console.log("Before create");
let newUser = new User({
...req.body,
activationCode: randtoken.uid(16),
activationExpiresIn: moment.utc().add(30, "minutes"),
email: req.body.email.toLowerCase()
});
console.log(newUser.save);
const userData = await newUser.save();
console.log("Saved");
let transaction = new DbTransaction({
transactionType: "insert",
modelName: "User",
data: userData,
clients: [process.env.DATABASE_CLIENT_ID],
isProcessed: false
});
await transaction
.save()
.then(d => console.log("Transaction updated successfully"))
await User.populate(userData, populateQuery, (err, data) => {
if (err) throw new Error(err);
return res
.status(201)
.send({ message: "User created successfully", user: data });
});
} catch (err) {
console.log(err);
console.log(err.kind);
return res.status(500).send({
message: err.message
});
}
};
I have tried different variants of javascript promise based work flow. Like Model.method().then().catch(), async try-await Model.method()-catch and lastly callback Model.method((err, data)=>{ //do something }).
None of the above conbination has worked. My observation is that mongoose just logs "done" into the console for this method but never action is never actually performed.
Your help is greatly appreciated, I have absolutely no idea why this is not working.
Thank you.
To all who made effort to assist, Thank you for the help.
I don't know why I am seeing the problem after posting here.
The issue was coming from not calling next in the middleware inside the model setup;
UserSchema.pre("save", function(next) {
if (!this.createdBy) this.createdBy = this._id;
if (!this.lastModifiedBy) this.lastModifiedBy = this._id;
});
Replace with;
UserSchema.pre("save", function(next) {
if (!this.createdBy) this.createdBy = this._id;
if (!this.lastModifiedBy) this.lastModifiedBy = this._id;
next();
});
Thank you all once again for your support.

Multiple async queries in nodejs (mongoose)

I am a nodejs newbie. I have two simple models, User and Story. Here is what I want to do:
I want to retrieve all stories that have {status:"public"} and store it in an array called retrievedStories.
Then for each story I want to use its "user" field (which contains the object id of the user) to lookup the name of the user from User
Then add a new key in each element of retrievedStories called authorName with the name of the user.
Here are the models:
const UserSchema = new mongoose.Schema({
googleId: {
type: String,
required: true
},
displayName: {
type: String,
required: true
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
image: {
type: String,
},
createdAt: {
type:Date,
default: Date.now()
}
})
const StorySchema = new mongoose.Schema({
title: {
type: String,
required: true,
trim: true
},
body: {
type: String,
required: true
},
status: {
type: String,
default: 'public',
enum: ['public', 'private']
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
createdAt: {
type:Date,
default: Date.now()
}
})
And here is what I tried, but doesn't work. The stories are retrieved but the authorName is not added. Any help (possibly a better way to do this?) will be highly appreciated!
router.get('/',async (req,res)=>{
try {
const retrievedStories = await Story.find(
{status: "public"}
)
await Promise.all(retrievedStories.map(async (story) =>{
const author = await User.findById(story.user)
story.authorName = author.displayName
}))
return res.json(retrievedStories)
} catch (error) {
console.log(error)
}
})
You can simplify your query by using populate to retrieve User's data:
router.get('/', async (req, res) => {
try {
const retrievedStories = await Story.find({ status: 'public' })
.populate('user')
.exec();
return res.json(retrievedStories);
} catch (error) {
console.log(error);
}
});
You can then access User's displayName data on each Story by accessing story.user.displayName.
For more information on query population see the official docs.

Mongoose findById callback returns null despite existence of record

I'm confused with this. The err is valid if the record exists. Oppositely, the err is invalid if the record doesn't exist.
However, the article is always null, although the record is existent in database.
router.get("/:id", function (req, res) {
Article.findById(req.params.id, function(err, article) {
if (err) {
res.send(`Error: ${err}`);
} else {
//Print out "null"
console.log(article);
//Error occur
Article.updateOne({_id: req.params.id}, {$set:{views: article.views + 1}});
res.render("showArticle", { article: article});
}
});
});
Article model:
var mongoose = require("mongoose");
const articleSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
description: {
type: String,
required: false
},
content: {
type: String,
required: true
},
createdDate: {
type: Date,
default: Date.now
},
views: {
type: Number,
default: 0
}
});
module.exports = mongoose.model("Article", articleSchema);
After searching for hours, OK... it's silly of me.
I haven't given the third parameter in mongoose.model.
Change:
module.exports = mongoose.model("Article", articleSchema);
To
module.exports = mongoose.model("Article", articleSchema, "Article");
I found that mongoose.prototype.model will automatically add a "s" at the end of the model name if there isn't collection name, which means, the Article collection will be named to Articles

How to reference a document when a PUT request is made

I am building an app of Todo Lists, and each list will have an x amount of tasks. The problem is I thought i could do something like this in the taskschema to reference the list the task belongs to:
list: {
type: mongoose.Schema.Types.ObjectId, ref: 'list'
}
Here´s the full code of my models:
const mongoose = require('mongoose')
const listSchema = new mongoose.Schema({
title: {
type: String,
unique: false,
required: [true, 'debes escribir un titulo']
},
createdAt: {
type: Date,
default: Date.now()
}
})
const mongoose = require('mongoose')
const taskSchema = new mongoose.Schema({
name: {
type: String,
unique: false,
required: true
},
doned: {
type: Boolean,
default: false
},
updatedAt: {
type: Date,
default: Date.now()
},
// a task belongs to a list:
list: {
type: mongoose.Schema.Types.ObjectId, ref: 'list'
}
})
But it seems there´s no much help in the web in how to make that work using that approach.
So I took a look at mongoDb documentation and they say they recommend using manual references
So i changed like this:
const mongoose = require('mongoose')
const taskSchema = require('./task')
const listSchema = new mongoose.Schema({
title: {
type: String,
unique: false,
required: [true, 'debes escribir un titulo']
},
createdAt: {
type: Date,
default: Date.now()
},
tasks: [
taskSchema
]
})
But now I´m clueless in how each time I create a task (a POST request to task is made) how I am at the same time will be related to a certain list.
Here´s my api routes for tasks:
routerTasks.post('/task', (req,res, next) => {
Task.create(req.body)
.then(task => res.send(task))
.catch(next)
})
routerTasks.put('/task/:idTask', (req, res) => {
Task.findByIdAndUpdate(req.params.idTask, req.body)
.then(task => res.send({nueva_informacion: task}))
.catch()
})
and for my lists:
routerLists.post('/list', (req, res, next) => {
List.create(req.body).then((list) => {
res.send(list)
}).catch(next)
})
routerLists.put('/list/:id', (req, res) => {
List.findByIdAndUpdate(req.params.id, req.body)
.then(list => res.send({nueva_informacion: list}))
})
My question is... maybe I should create the tasks in a put request of the newly created list? In that case, then the POST request of tasks are useless?
here´s the error that gives me when i try to add a Task and at the same time referencing it to a list:
routerTasks.post('/task/:listId', (req,res, next) => {
List.findOne({_id: req.params.listId}).then((record) => {
record.tasks.push(req.body);
record.save()
})
})
// TypeError: Invalid schema configuration: `model` is not a valid type within the array `tasks`

Mongoose - can't call model.find() in post findOneAndUpdate hook

Summary
In Mongoose have a post findOneAndUpdate hook and inside of this hook I need to query the database. I'm trying to do a .find() on another model, however each time I do, I get the following error:
Error
TypeError: Users.find is not a function
at model.Query.<anonymous> (/Users/benjilightstone/Coding/eSports-node-RESTful-API/api/models/fortniteUsers.js:29:32)
I have tried running the exact same .find() in one of my express routes and it works perfectly. I have checked the require() for Users and it's imported correctly. I have no idea why I'm getting this error and would love some help!
Code
fortniteUsers.js (Model with post hook)
const mongoose = require("mongoose");
const Users = require("./users");
const uniqueValidator = require("mongoose-unique-validator");
const statsFieldsSchema = require("./statsFields");
const fnUserPlatformSchema = {
//this is so that have a unique entry for a username &platform combo
fnUser: { type: String, require: true },
platform: { type: String, enum: ["pc", "xb1", "psn"], require: true }
};
//TODO took out updated at because the record shouldn't get updated?
//TODO think about usecase of Fortnite user changing their username
const fortniteUserSchema = mongoose.Schema({
// pass a javascript object that defines the schema
fnUserPlatform: { type: fnUserPlatformSchema, unique: true, require: true },
createdAt: { type: Date, require: true },
hasAccount: { type: Boolean, require: true, default: false },
updatedAt: { type: Date, require: false },
lifeTimeStats: { type: statsFieldsSchema, require: true }
});
fortniteUserSchema.post("findOneAndUpdate", async function(fortniteUser, next) {
try {
console.log("inside fortniteUser post hook", typeof fortniteUser._id);
const fnUserId = String(fortniteUser._id);
console.log("fnUserId", fnUserId);
// const userId = await User.find({ fnUser: fnUserId });
const userId = await Users.find({ fnUser: "5ccb08198f52f40117e950b3" });
console.log("userId", userId);
} catch (err) {
console.log("error in post hook", err);
}
});
fortniteUserSchema.plugin(uniqueValidator);
module.exports = mongoose.model("FortniteUser", fortniteUserSchema);
users.js (User model imported in fortniteUsers.js)
const mongoose = require("mongoose");
const FortniteUsers = require("./fortniteUsers");
require("mongoose-type-email");
const userSchema = mongoose.Schema({
// pass a javascript object that defines the schema
fnUser: {
type: mongoose.Schema.Types.ObjectId,
ref: "FortniteUser",
require: true
},
eSportsUsername: { type: String, require: true },
password: { type: String, require: true, minlength: 5 },
email: { type: mongoose.SchemaTypes.Email, require: true, unique: true },
ageConfirmed: { type: Boolean, require: true },
createdAt: { type: Date, require: true },
updatedAt: { type: Date, require: false }
});
userSchema.pre("save", function() {
console.log("inside pre save users.js");
console.log("docToSave", this); // QUESTION: how would I pass in req.body.fnUser
FortniteUsers.findOne({
fnUserPlatform: { username: req.body.fnUser, platform: "psn" }
})
.then(result => {
console.log("result in pre", result);
})
.catch(err => console.log("error i expect", err));
});
userSchema.post("save", function(user) {
//TODO where is user gettting passed from, I dont really understand this
console.log("we're in post save ... ", user);
FortniteUsers.findOneAndUpdate(
{ _id: user.fnUser },
{ $set: { hasAccount: true } },
function(err, doc) {
if (err) {
console.log("error in mongoose userSchema.post", err);
}
}
);
});
module.exports = mongoose.model("User", userSchema);
Look like the problem is because you require fortniteUsers and users in each other so one of them is not yet exported when call inside the other.
To verify this, you can console.log(FortniteUsers) and console.log(Users) after require them. You can see that FortniteUsers is Model {FortniteUsers} but Users is just {}.
You can solve it by moving this line const FortniteUsers = require("./fortniteUsers"); to be after the exports in users.js (not sure this is the good way but it works).

Categories