I export the model DemandeTransports from this file :
//#/components/database/model/Schema.js
import { Schema } from "mongoose";
import mongoose from "mongoose";
const userSchema = new Schema({
email: { type: String, index: true, unique: true, required: true },
password: { type: String, required: true },
role: { type: String, required: true },
infos: Map,
});
const Users = mongoose.models?.user || new mongoose.model("user", userSchema);
const demandeTransportSchema = new Schema({
date: { type: Date, required: true },
user: { type: Object, required: true },
values: { type: Object, required: true },
});
const DemandeTransports =
mongoose.models?.demandeTransport ||
new mongoose.model("demandeTransport", demandeTransportSchema);
console.log(DemandeTransports.findOne);
export { Users, DemandeTransports };
Which log (on server): [Function: findOne]
But when I try to import the model in this file :
//#/lib/getAllDemandesFromUser.js
import connectMongo from "#/components/database/conn";
import { DemandeTransports } from "#/components/database/model/Schema";
export default function getAllDemandesFromUser(email) {
console.log("JSON.stringify(DemandeTransports)");
console.log(JSON.stringify(DemandeTransports));
connectMongo().catch((error) =>
res.status(500).json({
error: "La connection à la bdd mongo a échoué avec l'erreur : " + error,
})
);
const result = DemandeTransports.findOne({ "user.email": email });
return result;
}
I get
TypeError: components_database_model_Schema__WEBPACK_IMPORTED_MODULE_1_.DemandeTransports.findOne is not a function
And DemandeTransports is logged as undefined, and I can't figure out why.
I just understood :
My basis error was that I tried to connect to the mongodb while being in client side, which is impossible.
I transfered all my call to the db in a getServerSideProps function :
export async function getServerSideProps(context) {
const session = await unstable_getServerSession(
context.req,
context.res,
authOptions
);
// Fetch data from external API
connectMongo().catch((error) =>
console.log("Erreur lors de la connection à la bdd : " + error)
);
const result = await DemandeTransports.findOne({
"user.email": session.user.email,
});
const result2 = result.toObject();
console.log(result.toObject());
// Pass data to the page via props
return { props: { result2 } };
}
And now it works perfectly fine.
Related
I’m pretty new to using Mongoose and can’t seem to find a fix. I have two schema’s; postSchema, commentSchema. The first one is for a post and the second is for comments that are stored within the post. Both schema’s have a map field to store likes. The post likes field’s setter and getter work when I try to update but when I try to do the same for the comments it gives me an error that the set or get is not a function. When I check if the likes are an instance of a map, the post likes will return true, while the comments like will return false. If anyone could help or direct me in the right direction it would be greatly appreciated.
Here is the code that I'm working with. When I create a comment to add to a post, the comment.likes checks as a Map. After I update the post I make a call to get all the post's and I rechecked that the comment.likes is a Map, but now it turns out false.
import mongoose from 'mongoose';
const postSchema = mongoose.Schema(
{
userId: {
type: String,
required: true,
},
userName: {
type: String,
required: true,
},
picturePath: {
type: String,
default: '',
},
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
likes: {
type: Map,
of: Boolean,
default: new Map(),
},
comments: {
type: Array,
default: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }],
},
},
{ timestamps: true }
);
const Post = mongoose.model('Post', postSchema);
export default Post;
import mongoose from 'mongoose';
const commentSchema = mongoose.Schema(
{
postId: {
type: String,
required: true,
},
userId: {
type: String,
required: true,
},
userName: {
type: String,
required: true,
},
picturePath: {
type: String,
default: '',
},
description: {
type: String,
required: true,
},
likes: {
type: Map,
of: Boolean,
default: new Map(),
},
},
{ timestamps: true }
);
const Comment = mongoose.model('Comment', commentSchema);
export default Comment;
export const addComment = async (req, res) => {
try {
const { id } = req.params;
const { userId, picturePath, description } = req.body;
const user = await User.findById(userId);
const newComment = new Comment({
id,
userId,
userName: user.userName,
picturePath,
//likes: {},
description,
});
newComment.set('likes', new Map());
console.log(newComment.likes instanceof Map);
const upDatedPost = await Post.findByIdAndUpdate(
id,
{ $push: { comments: newComment } },
{ new: true }
);
const allPost = await Post.find();
console.log(allPost[0].comments[2].likes instanceof Map);
res.status(200).json(allPost);
} catch (err) {
console.log('err');
res.status(404).json({ message: err.message });
}
};
This works for the post.likes.
export const likePost = async (req, res) => {
try {
const { id } = req.params;
const { userId } = req.body;
const post = await Post.findById(id);
const isLiked = post.likes.get(userId);
if (isLiked) {
post.likes.delete(userId);
} else {
post.likes.set(userId, true);
}
const upDatedPost = await Post.findByIdAndUpdate(
id,
{ likes: post.likes },
{ new: true }
);
res.status(200).json(upDatedPost);
} catch (err) {
res.status(404).json({ message: err.message });
}
};
This doesn’t work. When I check if element.likes is an instanceOf Map it gives back false, but for post.likes it returns true. Updated with the console.log's.
export const likeComment = async (req, res) => {
try {
const { id } = req.params;
const { postId, userId } = req.body;
let post = await Post.findById(postId);
let comments = post.comments;
console.log('comments: ', comments);
console.log('likes: ', comments[0].likes);
console.log(
'Is likes an instanceof Map: ',
post.comments[0].likes instanceof Map
);
//comments[0].likes.set(userId, true);
//post.comments[0].set('likes', new Map());
//console.log(comments[6].likes);
// comments.forEach((element) => {
// if (element._id.toString() === id) {
// element.likes.set(userId, true);
// }
// });
res.status(200).json(post);
} catch (err) {
res.status(404).json({ message: err.message });
}
};
Here is the output fro the console.log's.
comments: [
{
userId: '63dc0274bd8c03b1e417cfc4',
userName: 'dummyUserThree',
picturePath: '',
description: 'Likes still not working',
_id: new ObjectId("63e13f26603a052fc8f16b09"),
likes: {}
}
]
likes: {}
Is likes an instanceof Map: false
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.
So, i have a cart model which references Product model
`
import * as mongoose from "mongoose";
import { Schema } from "mongoose";
export type Product = {
productTitle: string;
};
const ProductSchema: Schema = new Schema<Product>(
{
productTitle: {
type: String,
required: [true, "productTitle is required"],
},
},
{
timestamps: true,
}
);
const Product = mongoose.model<Product>("Product", ProductSchema);
export default Product;
import * as mongoose from "mongoose";
import { Schema, Types } from "mongoose";
import { Product } from "./product.model";
type CartType = {
createdAt: number;
updatedAt: number;
userId: Types.ObjectId;
products: Product[];
};
const CartSchema: Schema = new Schema<CartType>(
{
createdAt: Number,
updatedAt: Number,
userId: {
type: Schema.Types.ObjectId,
ref: "User",
required: [true, "The user id is required"],
},
products: [
{
type: Schema.Types.ObjectId,
ref: "Product",
},
],
},
{
timestamps: true,
}
);
const Cart = mongoose.model<CartType>("Cart", CartSchema);
export default Cart;
`
This is my cart route
import express, { Request } from "express";
const router = express.Router();
import Cart from "../models/cart.model";
import { Product } from "../models/product.model";
interface ReqWithCart extends Request {
cart?: Record<string, any>;
}
router.param("userId", async (req: ReqWithCart, res, next, userId) => {
try {
const cart = await Cart.findOne({ userId: userId });
if (!cart) {
return res.status(400).json({ message: "Cart not found" });
}
req.cart = cart;
next();
} catch (error) {
res.status(400).json({
message: "There was some problem while retriving your cart",
error,
});
}
});
router
.route("/:userId")
.get(async (req: ReqWithCart, res) => {
try {
let cart = req.cart;
console.log(cart, 'asds');
if (cart) {
cart = await cart.populate({ path: "products", ref: 'Product' });
}
console.log(cart, "💕");
res.status(200).json({ cart: cart?.products });
} catch (error) {
res.status(400).json({
message: "There was some problem while retriving your cart",
error,
});
}
})
export { router as cart };
adding cart is working fine and adds object ids to the cart like this
{
_id: new ObjectId("634afc0ff6dbfb6c900997bb"),
userId: new ObjectId("634afc0ef6dbfb6c900997ba"),
products: [
new ObjectId("634a5494b3cb7ef6e37758a7"),
new ObjectId("634a5494b3cb7ef6e37758ab")
],
createdAt: 1665858575008,
updatedAt: 1668014234869,
__v: 10
}
but while using the get route, populate doesn't work and returns empty array like this
{
_id: new ObjectId("634afc0ff6dbfb6c900997bb"),
userId: new ObjectId("634afc0ef6dbfb6c900997ba"),
products: [],
createdAt: 1665858575008,
updatedAt: 1668014234869,
__v: 10
}
I don't know how to solve this as i am new to express and mongo world, can anyone please help me with this!!!
I was expecting the cart response object to be filled with products but instead got empty array
So I have two schemas user and driver they both have latitude and longitude attributes.
At some point I want to query the database for nearby drivers, I will be sending the user's current location (latitude and longitude) and I have a function to calculate the distance between two points.
I am trying to do something like this:
find all drivers with distance less than 2 KM using my function ( the function is called calculateDistance).
In code this will be like this:
const drivers = await Driver.find();
const driversToReturn = drivers.filter(
driver => calculateDistance(userLat, userLong, driver.latitude, driver.longitude) <= 2
);
res.status(200).json({
drivers: driversToReturn
});
but I don't think this is the best way to do it, I've checked the mongoose virtuals but we can't pass params (userLat and userLong) to the get method of a virtual and I don't think instance methods are the solution.
so how should I do this?
Thanks
EDIT
Driver Model
const mongoose = require("mongoose");
const { Schema } = mongoose;
const driverSchema = new Schema(
{
/** Required Attributes */
name: { type: String, required: true },
carBrand: { type: String, required: true },
plateNumber: { type: String, required: true },
password: { type: String, required: true },
phoneNumber: { type: Number, required: true },
price: { type: Number, required: true },
latitude: { type: Number, required: true },
longitude: { type: Number, required: true },
/** Not Required Attributes */
rating: { type: Number, required: false },
},
{
timestamps: true,
}
);
const Driver = mongoose.model("Driver", driverSchema);
module.exports = Driver;
User Model
const mongoose = require("mongoose");
const { Schema } = mongoose;
const userSchema = new Schema(
{
/** Required Attributes */
name: { type: String, required: true },
password: { type: String, required: true },
phoneNumber: { type: Number, required: true },
latitude: { type: Number, required: true },
longitude: { type: Number, required: true },
},
{ timestamps: true }
);
const User = mongoose.model("User", userSchema);
module.exports = User;
Users Controller
const Driver = require("../models/driver");
const Order = require("../models/order");
const calculateDistance = require("../utils/calculateDistance");
const CIRCLE_RADIUS_IN_KM = 2;
exports.getNearbyDrivers = async (req, res, next) => {
try {
const userLat = req.body.userLat,
userLong = req.body.userLong,
drivers = await Driver.find();
const driversToReturn = drivers.filter(
(driver) =>
calculateDistance(
userLat,
userLong,
driver.latitude,
driver.longitude
) <= CIRCLE_RADIUS_IN_KM
);
res.status(200).json({
drivers: driversToReturn,
});
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};
Here is some code from the documentation of Mongoose that can help you with that I think :
const denver = { type: 'Point', coordinates: [-104.9903, 39.7392] };
return City.create({ name: 'Denver', location: denver }).
then(() => City.findOne().where('location').within(colorado)).
then(doc => assert.equal(doc.name, 'Denver'));
and here is the link : https://mongoosejs.com/docs/geojson.html
how is everything ? I really need your help!
I'm building an API to register authenticated users, with storage in the mongo atlas database (cloud). I'm currently experiencing the following error: TypeError subscription error: User.hashPassword is not a function. I've done several researches, in several questions here on stackoverflow and on other sites, after testing all the solutions the error persists.
my user.model.js file looks like this:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const bcrypt = require('bcrypt');
const userSchema = new Schema(
{
userName: { type: String, unique: true, required: true },
email: { type: String, required: true, unique: true },
emailToken: { type: String, default: null },
emailTokenExpires: { type: Date, default: null },
active: { type: Boolean, default: false},
password: { type: String, required: true},
resetPasswordToken: { type: String, default: null },
resetPasswordExpires: { type: Date, default: null },
emailToken: {type: String, default: null},
emailTokenExpires: {type: Date, default: null},
},
{
timestamps: {
createdAt: "createdAt",
updatedAt: "updatedAt",
},
}
);
const User = mongoose.model("user", userSchema);
module.exports.hashPassword = async (password) => {
try {
const salt = await bcrypt.genSalt(10); // 10 rounds
return await bcrypt.hash(password, salt);
} catch (error) {
throw new Error("Hashing failed", error);
}
};
module.exports = User;
and my user.controller.js file looks like this:
const Joi = require("joi");
require("dotenv").config();
const { v4: uuid } = require("uuid");
const { sendEmail } = require("./helpers/mailer");
const User = require("./user.model");
//Validate user schema
const userSchema = Joi.object().keys({
email: Joi.string().email({ minDomainSegments: 2 }),
password: Joi.string().required().min(4),
confirmPassword: Joi.string().valid(Joi.ref("password")).required(),
});
exports.Signup = async (req, res) => {
try {
const result = userSchema.validate(req.body);
if (result.error) {
console.log(result.error.message);
return res.json({
error: true,
status: 400,
message: result.error.message,
});
}
//Check if the email has been already registered.
var user = await User.findOne({
email: result.value.email,
});
if (user) {
return res.json({
error: true,
message: "Email is already in use",
});
}
const hashPassword = await User.hashPassword(result.value.password);
const id = uuid(); //Generate unique id for the user.
result.value.userId = id;
//remove the confirmPassword field from the result as we dont need to save this in the db.
delete result.value.confirmPassword;
result.value.password = hashPassword;
let code = Math.floor(100000 + Math.random() * 900000); //Generate random 6 digit code.
let expiry = Date.now() + 60 * 1000 * 15; //Set expiry 15 mins ahead from now
const sendCode = await sendEmail(result.value.email, code);
if (sendCode.error) {
return res.status(500).json({
error: true,
message: "Couldn't send verification email.",
});
}
result.value.emailToken = code;
result.value.emailTokenExpires = new Date(expiry);
const newUser = new User(result.value);
await newUser.save();
return res.status(200).json({
success: true,
message: "Registration Success",
});
} catch (error) {
console.error("signup-error", error);
return res.status(500).json({
error: true,
message: "Cannot Register",
});
}
};
Error displayed in terminal:
Danilo#DANILO-PC D:\Meus Documentos\Área de Trabalho\api-auth-pokestore
$ node app.js
Server started listening on PORT : 5000
Database connection Sucess.
signup-error TypeError: User.hashPassword is not a function
at exports.Signup (D:\Meus Documentos\Área de Trabalho\api-auth-pokestore\src\users\user.controller.js:39:37)
at processTicksAndRejections (internal/process/task_queues.js:94:5)
image terminal
Look at this part of your code:
module.exports.hashPassword = async (password) => { ... };
module.exports = User;
You're setting hashPassword in your exports, then completely replacing your exports with User. You probably wanted to do something like this instead:
User.hashPassword = async (password) => { ... };
module.exports = User;
or move your module.exports.hashPassword = ... so it's after the module.exports = ....