I am trying to query my database like this
const Admin = require("./model/Admin");
module.exports = {
validateUser : (uName, pwd) => {
mongoose.connect("mongodb://127.0.0.1:27017/TeamDK")
//console.log("Uname: " + uName + ", Pwd: " + pwd)
res = Admin.findOne({ initial: "tt" }).exec()
}
}
In the case above, nothing is returned. The value of res is just null.
I also tried using a call back like this
res = Admin.findOne({ initial: "tt" }, (err, val) => {
console.log(res)
Using a callback, the output of res is different. I have added a screenshot of this, and only part of it is shown, as it is very big.
I'm sure there is a document in my Model collection. When using monosh like this
TeamDK> db.Admin.findOne({ initial: "tt" }), this is what I get
{
_id: ObjectId("63ebbd6c59097f4a25f23d31"),
firstName: 'Test',
initial: 'tt',
lastName: 'Unknown',
email: 'test#gg.com',
password: '123',
role: 4
}
If it's of any use, my model looks like this:
const adminSchema = mongoose.Schema({
firstName : {
type : String,
required : [true, "Why no name?"]
},
initial: {
type: String,
required: [true, "Why no initials?"],
index: {unique: true }
},
lastName : {
type : String,
required : [true, "Why no last name?"]
},
email : {
type : String,
required : [true, "Then how are we gonna contact you?"],
index: {unique: true }
},
password : {
type : String,
required : [true, "Come one man"]
},
dateCreate : {
type : Date,
default : Date.now
},
role : {
type : mongoose.Types.ObjectId,
ref : "role"
}
})
module.exports = mongoose.model("Admin", adminSchema);
I've spent almost a day trying to fix this, tried following guids on https://mongoosejs.com/ and tried looking for similar problems here on stackoverflow, but I just can't figure out what I'm doing wrong
------------------------- Update ---------------------------
I have also tried making the function async, and use await. I tried isolating the code in a new file and doing like this
const mongoose = require ("mongoose");
const Admin = require("./model/Admin");
async function testAdmin() {
await mongoose.connect("mongodb://127.0.0.1:27017/TeamDK")
res = await Admin.findOne({ initial: "tt" }).exec()
console.log(res)
}
testAdmin()
I also tried removing the exec(), doing
res = await Admin.findOne({ initial: "tt" })
I'm still getting null returned. Any other suggestions are most welcome
------------------------- Update ---------------------------
I have just noticed that if I do: res = await Admin.find() it works. Though it finds all the documents, and I only need a specific one, but it shows that it does contact the database. For some reason, it does not seem to accept the res = await Admin.findOne(...)
The .findOne is asynchronous, we must use await or callback to receive its result:
const Admin = require("./model/Admin");
module.exports = {
validateUser : async (uName, pwd) => {
await mongoose.connect("mongodb://127.0.0.1:27017/TeamDK") // It's better to put this connect function somewhere else, not in the Model
res = await Admin.findOne({ initial: "tt" });
return res;
}
}
Then use it a controller like this, example in Express
// The connect function is better here
// mongoose.connect("mongodb://127.0.0.1:27017/TeamDK")
app.post('/', async (req, res) => {
const result = await validateUser('username', 'password');
res.json(result);
})
I finally found out what the issue is. For some reason, it's as if the document that I was querying doesn't exist when I try to find it through node.js. I can find it when using mongosh though. I tried to query another document in the collection, and that one it found. So I tried yet another one, and that one it also finds. It seems to find all other, except this one (no matter which field I use as argument, it just returns null):
{
_id: ObjectId("63ebbd6c59097f4a25f23d31"),
firstName: 'Test',
initial: 'tt',
lastName: 'Unknown',
email: 'test#gg.com',
password: '123',
role: 4
}
Yet I created it exactly the same way as all the others. I have no idea why I can't query this in nodejs, and it's a problem if it should ever act like that in an application. Thankfully this is just practice. It's very likely that they error is at my side, but I haven't located it.
So should anyone experience the issue of not being able to access a document that you're certain is there (using nodejs), try see if you can access another document in the collection
Related
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))
Hi I'm new to MongoDB and Moongoose I'm trying to avoid my api's users to store on the Mongo database duplicated contact's name but seems like it's not working at all.
This is how I'm trying to do it right now the name and the phone number are mandatory and also the name must be unique otherwise it should throw an error.
const contactSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true
},
number: {
type: Number,
required: true
}
});
app.post('/api/persons', (request, response) => {
const body = request.body;
const person = new Contact({
name: body.name,
number: +body.number
});
person.save()
.then(saved => {
response.json(saved);
})
.catch(error => {
return response.status(400).json({
error: 'content missing'
});
});
})
If I send a post request with missing name or number it already throws an error but seems like it's not gettin the unique value validation.
Finally found a package that allows me to avoid duplicted entries on Mongo. I used this package following the documentation instructions:
https://github.com/blakehaswell/mongoose-unique-validator#readme
This is the code I had to write:
const uniqueValidator = require('mongoose-unique-validator');
const contactSchema = new mongoose.Schema({
name: {
type: String,
required: true,
unique: true
},
number: {
type: Number,
required: true
}
});
contactSchema.plugin(uniqueValidator);
the error of unique validation is weird so you can use unique-validator plugin, after that when you send a post request with missing name or number, the error is about required: true
Refer to validation
Validators are not run on undefined values. The only exception is the required validator.
Since both the fields(name and number) in your DB are required.
Instead of directly passing the request body to the query, you can do something like this.
const name = body.name;
const number = body.number;
if(!name || !number) {
// Return response saying either of the fields is empty.
// It's not a good practice to hit the DB with undefined values.
}
let personDetails = {
"name": name,
"contact": contact
};
const person = new Contact(personDetails);
Regarding the unique validation either you can use the unique-validator plugin as suggested by Mohammad Yaser Ahmadi or you can make a DB call to check if the name and number are unique and then hit the save method if that's is feasible for your database.
If you want both the fields name and number to be combined unique you can create Compound Index as follows:
contactSchema.index({ name: 1, number: 1 }, { unique: true });
You can read more on Compound Indexes here: https://docs.mongodb.com/manual/core/index-compound/
i have this Schema for a simple twitter app
const userSchema = new Schema ({
loginInfo: {
username: String,
email: String,
password: String
},
tweets: [{
content: String,
likes: Number,
comments: [{
owner: String,
content: String,
likes: Number
}]
}],
followers: [String],
following: [String]
})
and i want to make endpoint that return only the tweet that has the same _id that has been given as a params on the URL ..
I made that solution below and its working correctly but i believe there is a much better solution than this ..
const handleTweet = (User) => (req,res) => {
const { id } = req.params;
let theTweet = [];
User.findOne({ "tweets._id": id})
.then(user => {
user.tweets.forEach(tweet => {
if(tweet._id.toString() === id)
return theTweet.push(tweet)
})
res.json(theTweet)
})
.catch(err => res.json(err))
}
module.exports = handleTweet;
One more question : Is it better to make nested schemas like this or making a different models for each schema (in this case schema for User and another one for Tweets) ?
You should make the tweets into a different collection since you are querying based on that, and then you can use autopopulate when you need it.
Also instead of the foreach you could use Array.prototype.find
Hope this helps!
You can use the $push & findOneAndUpdate methods from mongoose. You can modify your example to be like this:
User.findOneAndUpdate(id, { $push: { tweets: req.body.tweet } }, {new: true})
.then((record) => {
res.status(200).send(record);
})
.catch(() => {
throw new Error("An error occurred");
});
Notice the {new: true} option, it makes the findOneAndUpdate method to return the record with the edit.
For your second question, it's recommended to split the modals to make your code more readable, maintainable and easy to understand.
Users are able to post items which other users can request. So, a user creates one item and many users can request it. So, I thought the best way would be to put an array of users into the product schema for who has requested it. And for now I just want to store that users ID and first name. Here is the schema:
const Schema = mongoose.Schema;
const productSchema = new Schema({
title: {
type: String,
required: true
},
category: {
type: String,
required: true
},
description: {
type: String,
required: true
},
userId: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
requests: [
{
userId: {type: Object},
firstName: {type: String}
}
],
});
module.exports = mongoose.model('Product', productSchema);
In my controller I am first finding the item and then calling save().
exports.postRequest = (req, res, next) => {
const productId = req.body.productId;
const userId = req.body.userId;
const firstName = req.body.firstName;
const data = {userId: userId, firstName: firstName};
Product.findById(productId).then(product => {
product.requests.push(data);
return product
.save()
.then(() => {
res.status(200).json({ message: "success" });
})
.catch(err => {
res.status(500).json({message: 'Something went wrong'});
});
});
};
Firstly, is it okay to do it like this? I found a few posts about this but they don't find and call save, they use findByIdAndUpdate() and $push. Is it 'wrong' to do it how I have done it? This is the second way I tried it and I get the same result in the database:
exports.postRequest = (req, res, next) => {
const productId = req.body.productId;
const userId = req.body.userId;
const firstName = req.body.firstName;
const data = {userId: userId, firstName: firstName};
Product.findByIdAndUpdate(productId, {
$push: {requests: data}
})
.then(() => {
console.log('succes');
})
.catch(err => {
console.log(err);
})
};
And secondly, if you look at the screen shot is the data in the correct format and structure? I don't know why there is _id in there as well instead of just the user ID and first name.
Normally, Developers will save only the reference of other collection(users) in the collection(product). In addition, you had saved username also. Thats fine.
Both of your methods work. But, second method has been added in MongoDB exactly for your specific need. So, no harm in using second method.
There is nothing wrong doing it the way you have done it. using save after querying gives you the chance to validate some things in the data as well for one.
and you can add additional fields as well (if included in the Schema). for an example if your current json return doesn't have a field called last_name then you can add that and save the doc as well so that's a benefit..
When using findById() you don't actually have the power to make a change other than what you program it to do
One thing I noticed.. In your Schema, after you compile it using mongoose.modal()
export the compiled model so that you can use it everywhere it's required using import. like this..
const Product = module.exports = mongoose.model('Product', productSchema);
I have a schema that has an id field that is set to a string. When I use collection.find({id: somenumber}) it returns nothing.
I've tried casting somenumber to a string and to a number. I've tried sending somenumber through as a regex. I've tried putting id in quotes and bare... I have no idea what's going on. Any help and input would be appreciated.
Toys.js
var Schema = mongoose.Schema;
var toySchema = new Schema( {
id: {type: String, required: true, unique: true},
name: {type: String, required: true},
price: Number
} );
My index.js is as such
app.use('/findToy', (req, res) => {
let query = {};
if (req.query.id)
query.id = req.query.id;
console.log(query);
// I've tried using the query variable and explicitly stating the object as below. Neither works.
Toy.find({id: '123'}, (err, toy) => {
if (!err) {
console.log("i'm right here, no errors and nothing in the query");
res.json(toy);
}
else {
console.log(err);
res.json({})
}
})
I know that there is a Toy in my mongoDB instance with id: '123'. If I do Toy.find() it returns:
[{"_id":"5bb7d8e4a620efb05cb407d2","id":"123","name":"Dog chew toy","price":10.99},
{"_id":"5bb7d8f7a620efb05cb407d3","id":"456","name":"Dog pillow","price":25.99}]
I'm at a complete loss, really.
This is what you're looking for. Visit the link for references, but here's a little snippet.
For the sake of this example, let's have a static id, even though Mongo creates a dynamic one [ _id ]. Maybe that what is the problem here. If you already a record in your DB with that id, there's no need for adding it manually, especially not the already existing one. Anyways, Drop your DB collection, and try out this simple example:
// Search by ObjectId
const id = "123";
ToyModel.findById(id, (err, user) => {
if(err) {
// Handle your error here
} else {
// If that 'toy' was found do whatever you want with it :)
}
});
Also, a very similar API is findOne.
ToyModel.findOne({_id: id}, function (err, toy) { ... });