mongoose findById using async await - node.js

I am trying to update a collection using async/await. Below is my code:
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/mongo-exercises')
.then(() => {
console.log('Connected to MongoDB');
UpdateCourse("5a68fdd7bee8ea64649c2777");
})
.catch(error => console.error('Could not connect to MongoDB : ' + error));
const courseSchema = mongoose.Schema({
name: String,
author: String,
tags: [String],
date: Date,
isPublished: Boolean,
price: Number
});
const Course = mongoose.model('course', courseSchema);
async function UpdateCourse(id) {
console.log(`Inside Update Course. Finding ${id}`);
const course = await Course.findById(id);
console.log(`Course: ${course}`);
if(!course)
return;
course.isPublished = true;
course.author = 'Another Author';
//course.set({isPublished: true, author: 'Another Author'});
const saved = await course.save();
console.log(saved);
}
I query the collection in mongo shell which produces the below output:
In the UpdateCourse() method I am getting null as value for course. I do have the id in the collection. Could anybody tell me why I am getting this error while using async/await.
I tried changing findById() -> findOne({_id: id}). Same error. I tried changing findById() -> find({_id: id}) here I am getting UnhandledPromiseRejectionWarning: Unhandled promise rejection.. Not understanding why.

The _id value in the document you're trying to find is a String, not an ObjectId. So you need to update your schema to define _id as a String; otherwise Mongoose will cast any _id values in your queries to the default _id type of ObjectId (resulting in the query not matching the document).
const courseSchema = mongoose.Schema({
_id: String,
name: String,
author: String,
tags: [String],
date: Date,
isPublished: Boolean,
price: Number
});
Having said all that, you probably want to update your documents to use ObjectId values for _id instead of String, as it's more efficient.

Related

empty result when getting data from mongodb with mongoose and node js

I'm trying to fetch all my documents from a collection in my MongoDb DB but I can't do it. I have absolutely no error but it just returns an empty array in my console.
Model :
import mongoose from "mongoose";
const websiteSchema = mongoose.Schema({
id: {type: String},
name: {type: String, required: true},
url: {type: String, required: true},
note: {type: Number, required: true}
});
export default mongoose.model("Website", websiteSchema);
File in which I want to use the data :
import express from 'express';
import Website from '../models/website.js';
const routerWebsiteList = express.Router();
routerWebsiteList.get('/website-list', async function(req, res, next) {
try {
const websitesToCrawl = await Website.find({});
console.log(websitesToCrawl);
} catch (error) {
res.status(500).json({message : "An error occured"});
}
})
export default routerWebsiteList;
All I get in my console is [].
My data in my database seems good too :
Accully everything looking fine maybe you can use
require for import files
const name = require('name')
and for the export file :
module.exports = routerWebsiteList
after that be sure you connected your database correct like this
async function database() {
await mongoose
.connect(process.env.DATABASE_URL)
.then(() => {
console.log("Database Coonected");
})
.catch((err) => {
console.log(err);
});
}
database()
Last detail is you don't need to put id on mongoose schema just remove it and finally change your model like this
const mongoose = require("mongoose");
const websiteSchema = mongoose.Schema({
name: {type: String, required: true},
url: {type: String, required: true},
note: {type: Number, required: true}
});
const Website = mongoose.model("Website", websiteSchema);
module.exports = Website
I hope that will be helpful. If you will be stuck somewhere feel free to type here again.
I finally found what was the problem. The mongoose Schema was looking in a wrong collection named "websites". All I had to do was to specified the collection name in my model as following : ("websitesToCrawl" is the collection name)
export default mongoose.model("Website", websiteSchema, "websitesToCrawl");

Can't query a record in MongoDB when using "$" selector

I have a weird problem when using NodeJS with Mongoose when querying a record in MongoDB.
I have a Product model file is like this:
const mongoose = require("mongoose");
const productSchema = new mongoose.Schema({
name: String,
brand: String,
shorDescription: String,
description: String,
price: Number,
salePercent: Number,
rating: Number,
color: String,
size: [String],
});
const Product = mongoose.model("Product", productSchema);
module.exports = Product;
And in the controller file, my code is like this:
const Product = require("../models/product.model");
exports.getProducts = async (req, res) => {
const products = await Product.find({ rating: { $lte: "5" } });
console.log(`products: ${products}`);
res.json({
products: products,
});
};
Product.find({}) works perfectly -> returns all the records in the product collection
Product.find({brand: "Nike"}) still works fine -> returns all the "Nike" products.
the weird thing is when I use $ selector in Product.find({ rating: { $lte: "5" } }), I receive nothing while I have several products which are match the condition in the product collection.
Someone help me :(((
MongoDB query operators are type sensitive. The problem here is that the query expression is a string ("5"), but the data is a number (e.g. 5). Since the types are incomparable, they will never match the $lte expression.
For instance, the query for {rating: {$lte: "5"}} will match documents like:
{rating: "5"}
{rating: "4.5"}
{rating: "25"}
{rating: ""}
but not like:
{rating: 5}
{rating: 4.5}

Unable to update MongoDB collection by matching _id

First, I Registered a user using His email and password.
Now if
I try to Update or Make user details by matching the Id assigned by the Mongo Database while registering the user.
it's not accepting it.
error is like this
Parameter "filter" to find() must be an object, got 60b10821af9b63424cf427e8
if I parse it like
Model.find(parseInt(req.params.id))
it shows a different error.
Well here's the Post Request
//Post request to create user details by matching Id.
// Id I am trying to match is the id that was given by the database
app.post("/user/:id", async(req, res) => {
console.log("not found");
if (await Model.find(req.params.id)) {
const users = new Model({
fName: req.body.fName,
sName: req.body.sName,
birth: req.body.birth,
phone: req.body.phone,
SSN: req.body.SSN
});
const result = await users.save();
console.log(result);
return res.send({
"Success": true,
});
} else {
console.log(req.params.id);
res.status(404).send({ "message": false });
}
});
Here's the schema
const LoginSchema = new mongoose.Schema({
email: { type: String, required: true },
password: { type: String, required: false },
otp: String,
token: String,
fName: String,
sName: String,
birth: Number,
phone: Number,
SSN: Number
});
Here are the headers I used
const express = require("express");
const app = express();
const mongoose = require("mongoose");
app.use(express.json());
app.use(express.urlencoded({ extend: true }));
Database id assigned which I use
{
_id: 60b1131271129a3cf8275160,
email: 'Pak#gmail.com',
password: '$2b$10$FWAHu4lP9vn14zS/tWPHUuQJlO7mjAUTlPj.FliFAZmCNA23JA3Ky',
__v: 0
}
The error:
Parameter "filter" to find() must be an object, got 60b10821af9b63424cf427e8
means: You need to provide an object as the argument of the find() method, not a string ("60b10821af9b63424cf427e8" in this case). Moreover, find() will give you an array, if you find an item in the database, use findOne() instead.
Change from :
await Model.find(req.params.id)
to :
await Model.findOne({_id : req.params.id})
Another way is to use findById() method like this : await Model.findById(req.params.id)
Likely the error is caused by the fact that you're passing a string from the request when Mongoose is expecting an instance of mongoose.Types.ObjectId. You should be able to fix the problem by casting the string into said type.
await Model.find(mongoose.Types.ObjectId(req.params.id))

can't find documents by id

so I'm trying to update a document but it just doesn't work with _id but if I filter with "name" it works
I also tried with FindByID and it returns null
using mongoose version 5.0.18
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/mongo-exercises')
.then(() => console.log('connected to database :)'))
.catch(reason => console.log('Can not connect to data base',reason));
const courseSchema = mongoose.Schema({
name: String,
author: String,
tags: [String],
Date: { type:Date,default:Date.now },
isPublished: Boolean,
price: Number
});
const Course = mongoose.model('courses',courseSchema);
async function updateCourse(id){
let result = await Course.update({_id: id},{
$set:{
author: "some random dude",
isPublished: true
}
});
console.log('result: ',result);
}
updateCourse('5a68fde3f09ad7646ddec17e');
try using
//make sure you import Course module
Course.findByIdAndUpdate(id)
.then(response=>{
})
.catch(err=>{
})
I just had to re-import the collection without _id so it can regenerate them

How to set ObjectId as a data type in mongoose

Using node.js, mongodb on mongoHQ and mongoose. I'm setting a schema for Categories. I would like to use the document ObjectId as my categoryId.
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Schema_Category = new Schema({
categoryId : ObjectId,
title : String,
sortIndex : String
});
I then run
var Category = mongoose.model('Schema_Category');
var category = new Category();
category.title = "Bicycles";
category.sortIndex = "3";
category.save(function(err) {
if (err) { throw err; }
console.log('saved');
mongoose.disconnect();
});
Notice that I don't provide a value for categoryId. I assumed mongoose will use the schema to generate it but the document has the usual "_id" and not "categoryId". What am I doing wrong?
Unlike traditional RBDMs, mongoDB doesn't allow you to define any random field as the primary key, the _id field MUST exist for all standard documents.
For this reason, it doesn't make sense to create a separate uuid field.
In mongoose, the ObjectId type is used not to create a new uuid, rather it is mostly used to reference other documents.
Here is an example:
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Schema_Product = new Schema({
categoryId : ObjectId, // a product references a category _id with type ObjectId
title : String,
price : Number
});
As you can see, it wouldn't make much sense to populate categoryId with a ObjectId.
However, if you do want a nicely named uuid field, mongoose provides virtual properties that allow you to proxy (reference) a field.
Check it out:
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Schema_Category = new Schema({
title : String,
sortIndex : String
});
Schema_Category.virtual('categoryId').get(function() {
return this._id;
});
So now, whenever you call category.categoryId, mongoose just returns the _id instead.
You can also create a "set" method so that you can set virtual properties, check out this link
for more info
I was looking for a different answer for the question title, so maybe other people will be too.
To set type as an ObjectId (so you may reference author as the author of book, for example), you may do like:
const Book = mongoose.model('Book', {
author: {
type: mongoose.Schema.Types.ObjectId, // here you set the author ID
// from the Author colection,
// so you can reference it
required: true
},
title: {
type: String,
required: true
}
});
My solution on using ObjectId
// usermodel.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const ObjectId = Schema.Types.ObjectId
let UserSchema = new Schema({
username: {
type: String
},
events: [{
type: ObjectId,
ref: 'Event' // Reference to some EventSchema
}]
})
UserSchema.set('autoIndex', true)
module.exports = mongoose.model('User', UserSchema)
Using mongoose's populate method
// controller.js
const mongoose = require('mongoose')
const User = require('./usermodel.js')
let query = User.findOne({ name: "Person" })
query.exec((err, user) => {
if (err) {
console.log(err)
}
user.events = events
// user.events is now an array of events
})
The solution provided by #dex worked for me. But I want to add something else that also worked for me: Use
let UserSchema = new Schema({
username: {
type: String
},
events: [{
type: ObjectId,
ref: 'Event' // Reference to some EventSchema
}]
})
if what you want to create is an Array reference. But if what you want is an Object reference, which is what I think you might be looking for anyway, remove the brackets from the value prop, like this:
let UserSchema = new Schema({
username: {
type: String
},
events: {
type: ObjectId,
ref: 'Event' // Reference to some EventSchema
}
})
Look at the 2 snippets well. In the second case, the value prop of key events does not have brackets over the object def.
You can directly define the ObjectId
var Schema = new mongoose.Schema({
categoryId : mongoose.Schema.Types.ObjectId,
title : String,
sortIndex : String
})
Note: You need to import the mongoose module
Another possible way is to transform your _id to something you like.
Here's an example with a Page-Document that I implemented for a project:
interface PageAttrs {
label: string
// ...
}
const pageSchema = new mongoose.Schema<PageDoc>(
{
label: {
type: String,
required: true
}
// ...
},
{
toJSON: {
transform(doc, ret) {
// modify ret directly
ret.id = ret._id
delete ret._id
}
}
}
)
pageSchema.statics.build = (attrs: PageAttrs) => {
return new Page({
label: attrs.label,
// ...
})
}
const Page = mongoose.model<PageDoc, PageModel>('Page', pageSchema)
Now you can directly access the property 'id', e.g. in a unit test like so:
it('implements optimistic concurrency', async () => {
const page = Page.build({
label: 'Root Page'
// ...
})
await page.save()
const firstInstance = await Page.findById(page.id)
const secondInstance = await Page.findById(page.id)
firstInstance!.set({ label: 'Main Page' })
secondInstance!.set({ label: 'Home Page' })
await firstInstance!.save()
try {
await secondInstance!.save()
} catch (err) {
console.error('Error:', err)
return
}
throw new Error('Should not reach this point')
})

Resources