How to remove object from array in MongoDB - node.js

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

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.

How to check if a user id exists in the array before adding?

I have 2 models (TweetModel and RatingModel), and I want to add new user IDs to array retweets that have RatingModel, but I need to check if a user id exists in the array before adding to DB.
I will be grateful for the answer
RatingModel.findByIdAndUpdate(tweetId, { $push: { retweets: user._id } }).exec(async (err) => {
if (err) {
res.status(422).send()
} else {
res.json({
status: 'successful retweet',
data: await TweetModel.findById(tweetId),
})
}
})
RATING MODEL IN MONGODB

How to check if a document exisits in MongoDB

I am trying to check if a document exists in MongoDB and then based on that either update the document or create a new one. However only the if statement is being recorded. I have checked that the value of documentExists is null if no document is in mongo.
router.post("/mongo", async function (req, res) {
const documentExists = await Files.findOne({
_id: req.body.id,
});
if (documentExists) {
try {
Files.updateOne(
{ _id: documentExist._id },
{ flag: req.body.flag },
function (err, result) {
if (err) {
res.send(err);
} else {
res.send(result);
}
}
);
} catch (err) {
res.status(400).send(err);
}
} else {
CREATE NEW DOCUMENT
}
})
In your case you can use findOneAndUpdate to update if there is any existing document in the collection, if there is no matching document the query returns null.

Grabbing only one object out of an array of objects

I am using MongoDB and I am trying to grab a specific object based on its _id and all of the sibling elements as well. For example my array looks like this:
"blogs": [
{
"body": "default valuee",
"header": "another first",
"_id": "1234"
},
{
"body": "second default value",
"header": "second",
"_id": "5678"
}
]
And I am trying to grab the values that are beside the _id of 1234 (so the body,header and _id fields of just that object). I have tried a few Mongo queries but with no such luck. Any help would be great, cheers
My function is :
module.exports = function findBlog(db, id, callback){
var UserCollection = db.collection('users') //connect to business collection
UserCollection.findOne({ 'blogs._id': id }, {body: 1, header: 1, _id: { $elemMatch: { _id: id}}},function (err, user) {
if (err){
return callback({response: "3"})
}else if(!user){
return callback({response: "4"})
}else {
return callback({response: "2",data:user.blogs})
}
});
}
You should use something like this,
If you want all fields from blogs and user you can directly use,
UserCollection.find({ 'blogs._id': id }, { blogs:{ $elemMatch:{ _id: id }}},function (err, user) {
if (err){
return callback({response: "3"})
}else if(!user){
return callback({response: "4"})
}else {
return callback({response: "2",data:user.blogs})
}
});
}
If you need specific fields:
First parameter you will add condition: { 'blogs._id': id }
Second parameter you will add fields required: { "blogs.body": 1,"blogs.header": 1 }
UserCollection.findOne({ 'blogs._id': id }, { "blogs.body": 1,"blogs.header": 1 },function (err, user) {
if (err){
return callback({response: "3"})
}else if(!user){
return callback({response: "4"})
}else {
return callback({response: "2",data:user})
}
});
}
As I stated in a comment on the OP's question, the best way to to work this out is to create a Blog collection. You can then query this collection directly instead of querying the User collection.
You can still have the blogs property in the User model by linking a blog to a user. (see the Mongoose documentation on populate)

Fetching data with qraphQL by _id

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.

Resources