Fetching data with qraphQL by _id - node.js

I recently started working with GraphQL. I am able fetch the records from mongodb collections with the base of name, but if I try the same code to get the data by _id(mongodb generated id) I am getting null values for all fields.
Here is my sample code...
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
// To get a user based on id
getUser: {
type: UserType,
args: {
_id: {
description: 'The username of the user',
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: (root, {_id}) => {
//Connect to Mongo DB
return mongo()
.then(db => {
return new Promise(
function(resolve,reject){
//Query database
let collection = db.collection('users');
collection.findOne({ _id},(err,userData) => {
if (err) {
reject(err);
return;
}
console.log(userData);
resolve(userData);
});
})
});
}
},
and the sample query is:
{
getUser ( _id: "55dd6300d40f9d3810b7f656")
{
username,
email,
password
}
}
I am getting response like:
{
"data": {
"getUser": null
}
}
Please suggest me any modifications if required...
Thanq.

Because the "_id" field generated by mongoDB is not just a string, it is actually ObjectId("YOUR ID STRING HERE").
So in your query, mongoDB won't find any _id that is equal to the string you feed to it.
Try to use collection.findById() instead.

Related

mongo DB always update first document

I have a posts collection that has array of likes.I want to push object into likes array if user have not liked and pull if user has liked the post.I test my API but it always update first document of collection though I provided postId of other document.
schema.js
likes: [
{
userId: String,
isNotified: {
type: Boolean,
default: false,
},
email: String,
types: String,
},
],
API
router.post("/like", (req, res) => {
postModel.find(
{
"_Id": req.body.postId,
"likes.userId": req.body.userId,
},
(err, doc) => {
// console.log(doc)
if (!doc.length) {
postModel.updateOne(
{ "_Id": req.body.postId,},
{
$push: {
likes: {
userId: req.body.userId,
email: req.body.email,
// types: req.body.types,
},
},
},
(err, doc) => {
res.send("like");
}
);
} else {
// console.log("pull")
postModel.find(
{
"_Id": req.body.postId,
"likes.userId": req.body.userId,
},
(err, doc) => {
doc.map((e) => {
e.likes.map((x) => {
if (x.userId == req.body.userId) {
postModel.updateOne(
{
"_Id": req.body.postId,
"likes.userId": req.body.userId,
},
{
$pull: {
likes: {
userId: req.body.userId,
email:req.body.email
},
},
},
(err, doc) => {
res.send("unlike");
}
);
}
});
});
}
);
}
// res.send(doc);
}
);
// });
});
postman request
{
"email":"mahima#gmail.com",
"types":"like",
"postId":"6312c2d1842444a707b6902f",
"userId":"631452d0e1c2acf0be28ce43"
}
How to fix this,suggest an advice.Thanks in advance.
I'm not sure if I undrestand the logic, but here are couple of things that I think you can improve:
You are using find method to get a single document, you should use findOne method which return a single document (if exists) and not an array of documents. But in general when you have the _id value of a document, it's better to just use findById method which is much faster.
When you find a document, you can just modify it and call it's save method to write your changes to the database, there is no need to use updateOne. (please note that partital update has many advantages but in your case they don't seem necessary, you can read about it online.)
your API code can be something like this:
router.post("/like", (req, res) => {
const postId = req.body.postId
const userId = req.body.userId
postModel.findById(postId) // get the post
.then(post => {
if (post) { // check if post exists
// check if user has already liked the post
if (post.likes.find(like => like.userId == userId)){
// user has already liked the post, so we want to
// remove it from likes (unlike the post).
// I know this is not the best way to remove an item
// from an array, but it's easy to understand and it
// also removes all duplications (just in case).
post.likes = post.likes.filter(like => like.userId != userId)
// save the modified post document and return
return post.save(_ => {
// send success message to client
res.send("unlike")
})
} else {
// user has not liked the post, so we want to add a
// like object to post's likes array
post.likes.push({
userId: userId,
email: req.body.email // you can other properties here
})
// save the modified post document and return
return post.save(_ => {
// send success message to client
res.send("like")
})
}
} else { // in case post doesn't exist
res.status(404).send("post not found.")
}
})
.catch(err => {
// you can handle errors here
console.log(err.message)
res.send("an error occurred")
})
})
I didn't run the code, but it should work.

MongoDB - addToSet not adding element to array

"mongoose": "^5.12.2"
I have a schema named User. This schema has a field named "rol" of type string[] for a multiple rol application (User, Admin, Freetour, BarOwner, etc).
The function that adds a rol to a user is defined like this:
public addRolToUser = (idUser:string, newRol:string):Promise<IUser> => {
try{
return new Promise<IUser>((resolve, reject) => {
User.findByIdAndUpdate(idUser, { addToSet: {rol:newRol} }, {new:true}).then(user => {
return resolve(user);
}).catch(err => {
return reject(err);
});
});
}catch (e) {
throw e;
}
};
However this doesn´t update the "rol" field of the user. The following function should add the rol "FreeTour" to the user with the id returned by "petition.user".
public acceptPetition = async(req:Request, res:Response) => {
try{
return this.solFreeTourService.acceptPetition(req.body.idPetition).then(petition => {
let acceptPromise = new Promise((resolve, reject) => {
// Here I´m invoking the addRolToUser function
return this.userService.addRolToUser(petition.user, "FREETOUR").then((resUser)=>{
// resUser here has the same value for the "rol" field, didn´t get updated.
return resolve(petition);
}).catch(err=>{
return reject(err);
})
})
return acceptPromise.then(petition=>{
return res.status(200).json({petition});
}).catch(e=>{
res.status(400).json({ status: 400, message: "There has been an error." });
});
})
}catch (e) {
res.status(400).json({ status: 400, message: "There has been an error." });
}
}
I don't want repeated values in the "rol" array, hence pushing is not an option.
What am I doing wrong?
first of all, Welcome to StackOverflow! 👋
I have to assume that you might have something not working well together as you say you're using Mongoose and for such I've made a very simple project that you can look into in GitHub
where I create a very simple schema
const UserSchema = mongoose.Schema({
role: [{
type: String
}],
guid: {
type: String,
required: true
},
});
and then make use of the Mongoose API to create, update and find the user
const guid = uuidv4();
// create user
await UserModel.create({ guid });
log('user created');
["admin", "user", "admin"].forEach(async (role) => {
// add role to user
await UserModel.updateOne({ guid }, { $addToSet: { role } });
log(`user role updated with ${role}`);
});
// read user
const newUser = await UserModel.where({ guid }).findOne();
log(JSON.stringify(newUser, null, 2));
and the output is the expected one
user created
user role updated with admin
user role updated with user
user role updated with admin
{
"role": [
"admin",
"user"
],
"_id": "60a2397b1c488d4968d6ed46",
"guid": "26ccacbf-ddbc-4cbf-ac69-2da3235e156b",
"__v": 0
}
fell free to look into the source code, clone, run, and test, and notice that I'm using in fact the Mongo command as $addToSet

How to remove object from array in MongoDB

I have the following document structure:
And am trying to figure out how to delete a single object from the 'saved array', using the id in the object to select it (eg id 4182 will delete the object and all its properties at index 0). This was my attempt but not sure how to target it properly (No errors, but nothing updated):
let id = req.query.clicked_id;
console.log("\deleteSaved id:", id);
db.collection("users").updateOne(
{ username: config.username },
{ $unset: { id: id} },
(err, data) => {
if (err) {
console.log(err);
}
console.log("Item deleted from DB: ", id, data.result.nModified);
res.redirect("/saved");
}) ;
Thanks
you can find the answer very clear in the (MongoDB, remove object from array)
and my answer is
you can use $pull operator in mongodb documentation
to pull element from array
you can use this query
let id = req.query.clicked_id;
console.log("\deleteSaved id:", id);
db.collection("users").updateOne(
{ username: config.username },
{ $pull: {saved: { id: id } },
(err, data) => {
if (err) {
console.log(err);
}
console.log("Item deleted from DB: ", id, data.result.nModified);
res.redirect("/saved");
}) ;
this one will work fine

Upsert Mongoose Error

I'm pretty new to Mongoose/Mongo and node.js, so I suspect this is just a misunderstanding on my side, I have some problem when I try to upsert my object.
Here What have I try to use upsert in my code :
app.post("/api/orders/:id", async (req, res) => {
const { id, name, email, phone, data, item } = req.body;
const existingVisitor = await Visitor.findOne({ email: email.trim() });
if(existingVisitor){
delete Visitor._id;
}
const OrderSchema = await new Order({
orderDate: new Date(),
item: item
});
const visitor = await new Visitor(
{ email: email.trim() },
{
name: name,
email: email.trim(),
phone: phone,
data: data,
createDate: new Date(),
_user: req.params.id,
order: [OrderSchema]
},
{ upsert: true, setDefaultsOnInsert: true }
);
try {
await visitor.update();
console.log("Sucess!");
} catch (err) {
res.status(422).send(err);
}
When I'm Trying to test it in Postman, I got error result following error : After applying the update to the document {_id: ObjectId('59f1896ccabc4f12bc17e5c6') , ...}, the (immutable) field '_id' was found to have been altered to _id: null
What should I do to fix that error?

Mongoose deleting (pull) a document within an array, does not work with ObjectID

I have the following mongoose schema:
user = {
"userId" : "myId",
"connections":
[{
"dateConnectedUnix": 1334567891,
"isActive": true
}, {
"dateConnectedUnix": 1334567893,
"isActive": false
}]
}
I would like to delete the second item in the connections array, to get the following:
user = {
"userId" : "myId",
"connections":
[{
"dateConnectedUnix": 1334567893,
"isActive": false
}]
}
The following code does the job as expected:
userAccounts.update(
{ 'connections.isActive': false },
{ $pull: { 'connections.isActive':false }},
function (err, val) {
console.log(val)
}
);
But, I need to delete based on ObjectId. And the following goes does not work:
userAccounts.update(
{ 'connections._id': '1234-someId-6789' },
{ $pull: { 'connections._id': '1234-someId-6789' } },
function (err, val) {
console.log(val)
}
);
Any suggestions? I have been banging my head against the screen (aka Google, Stackoverflow, ...) for hours and have had no luck.
It seems that the above code would not work. It should not even have worked for the first example I gave.
In the end I was supported by this answer here: MongoDB, remove object from array
Here is my working code:
userAccounts.update(
{ userId: usr.userId },
{
$pull: {
connections: { _id : connId }
}
},
{ safe: true },
function removeConnectionsCB(err, obj) {
// ...
}
);
I have a document like
I have to delete address from address array
After searching lots on internet I found the solution
Customer.findOneAndUpdate(query, {$pull: {address: addressId}}, (err, data) => {
if (err) {
return res.status(500).json({ error: 'error in deleting address' });
}
res.json(data);
});
user: {
_id: ObjectId('5ccf3fa47a8f8b12b0dce204'),
name: 'Test',
posts: [
ObjectId("5cd07ee05c08f51af8d23b64"),
ObjectId("5cd07ee05c08f51af8d23c52")
]
}
Remove a single post from posts array
user.posts.pull("5cd07ee05c08f51af8d23b64");
user.save();
To use update with ObjectId, you should use ObjectId object instead of string representation :
var ObjectId = require('mongoose').Types.ObjectId;
userAccounts.update(
{ 'connections._id': new ObjectId('1234-someId-6789') },
{ $pull: { 'connections._id': new ObjectId('1234-someId-6789') } },
function (err,val) {
console.log(val)
}
);
use findByIdAndUpdate to remove an item from an array
You can do it in mongoose 5.4.x and above
const result = await User.findByIdAndUpdate(user_id, {
$pull: {
someArrayName: { _id: array_item_id }
}
}, { new: true });
The item from array will be removed based on provided property _id value
If you are using mongoose, no need to use the MongoDB stuff, I mean that's why we're using mongoose in the first place, right?
userAccounts.connections.pull({ _id: '1234-someId-6789'});
await userAccounts.save();
mongoose: 4.11.11
What have worked for me is the following syntax:
const removeTansactionFromUser = (userId, connectionId) => {
return User.findByIdAndUpdate(userId, { $pull: { "connections": connectionId} }, {'new': true} );
};
Mongoose support id in string format or ObjectId format.
Tip: new ObjectId(stringId) to switch from string to ObjectId
In mongoose 5.8.11, this $pull: { ... } didn't work for me, so far not sure why. So I overcame it in my controller this way:
exports.removePost = async (req, res, next) => {
const postId = req.params.postId;
try {
const foundPost = await Post.findById(postId);
const foundUser = await User.findById(req.userId);
if (!foundPost || !foundUser) {
const err = new Error(
'Could not find post / user.',
);
err.statusCode = 404;
throw err;
}
// delete post from posts collection:
await Post.findByIdAndRemove(postId);
// also delete that post from posts array of id's in user's collection:
foundUser.posts.pull({ _id: postId });
await foundUser.save();
res.status(200).json({ message: 'Deleted post.' });
} catch (err) {
// ...
}
};

Resources