NodeJs: how to assign additional objects to mongoose query response JSON - node.js

Using mongoose I am querying a list of posts and would like to determine whether or not the user has liked the image or not within the query function by adding a boolean to the response JSON. I am trying to do this in a for loop.
However, when I console.log(), the post with the field returns correctly but does not amend it to the JSON.
My function:
function(req, res) {
var isLiked, likeCount;
Post
.find(/* Params */)
.then(posts => {
for (var index in posts) {
posts[index].isLiked = posts[index].likes.includes(req.headers.userid)
console.log(posts[index]) // does not show 'isLiked' field in JSON
console.log(posts[index].isLiked) // response is correct
}
res.send(posts) // does not have 'isLiked field
})
},
Post schema:
var postSchema = new Schema({
userId: {
type: String,
required: true
},
caption: {
type: String,
required: false
},
likes: [{
type: String,
}]
});

To add properties to queries objects you should convert them to JS objects:
function getPosts(req, res) {
Post.find(/* Params */).then((posts) => {
const result = [];
for (const post of posts) {
const postObj = post.toObject();
postObj.isLiked = postObj.likes.includes(req.headers.userid);
result.push(postObj)
}
res.send(result);
});
}

Cuz
Post.find()
is not return an object, you can set prop isLiked to posts[index] but it's private.
Easy way to fix it is use lean() method to get return object
Post.find().lean()
.then(//do what you want)

Related

Update multiple documents instance in MongoDb collection with Mongoose. save() is not a function

Mongoose newbe here. I got the following function to update the references (deleting them) in the document Post when a Tag is deleted. When I call my GraphQl API this is what I got:
message": "posts.save is not a function"
The function in my gql resolver:
async deleteTag(root, { id }, context) {
const posts = await Post.find();
const tag = await Tag.findById(id);
if(!tag){
const error = new Error('Tag not found!');
error.code = 404;
throw error;
}
posts?.forEach(async (post) => {
await post.tags.pull(id);
})
await posts.save()
await Tag.findByIdAndRemove(id);
return true;
}
This is the Post model:
const PostSchema = new Schema({
body: {
type: String,
required: true
},
tags: {
type: [Schema.Types.ObjectId],
ref: 'Tag',
required: false
},
});
and this is the Tag model:
const TagSchema = new Schema(
{
name: {
type: String,
required: true
},
},
{ timestamps: true }
);
Looks like I can't call the method save() on the array of objects returned by Exercise.find()
I used the same pattern in other functions, the difference is that there I used .findById()
Any solution? Advice and best practice advide are super welcome.
You have to save the posts individually:
posts?.forEach(async (post) => {
await post.tags.pull(id);
await post.save();
})
Or use Model.updateMany() combined with the $pull operator.
FWIW, you should probably limit the number of matching Post documents by selecting only documents that have the specific tag listed:
await Post.find({ 'tags._id' : id });

how to get the existing collection in mongodb using mongose- Nodejs

In my mongodb i already had a collection and document
Now, i want to use this collection in my node-js using mongoose. how we do this.
const mongoose = require("mongoose");
const schema = mongoose.Schema;
const adminLogin = new schema({
name: { type: String, required: true },
password: { type: String, required: true }
})
module.exports = mongoose.model("adminDetails", adminLogin)
while doing this it is creating new collection. Unable to use the existing collection.
At first you need to make a GET method Router in your jsFile.
like this
app.get("/mainData", async (req, res) => {
const menuInfo = await Nutrients.find({});
res.json(menuInfo);
});
You can set and use VSCode extension "thunderClient"!
like this
enter image description here
setting your request method and URI endpoint
(when you user GET method to get some data in your case, you don't need to write something in request body)
Then, you can see your data on the 'response part' as an Object Data.
If you want to use your data on Front side on your Project, you can use like this!
(in my case, I used jQuery. )
function menu_show() {
$('#result_list').empty()
$.ajax({
type: 'GET',
url: '/mainData', //you need to write same url with your no3.
data: {},
success: function (response) {
console.log(response)
let rows = response['menus']
for (let i = 0; i < rows.length; i++) {
let menuName = rows[i]['menuName']
console.log(menuName)
}
}
}
This is my answer. Let me know if you've solved it!
the image 1 is the structure in the MongoDB. I want to read the data from that collection, below is the code using and the URL and output in post man.
route.get('/adminLogin', (request, response) => {
const data = adminDetails.find({}, (err, result) => {
if (err) {
console.log(err)
} else {
res.json(result)
}
})
})
http://localhost:5000/admin/adminLogin

Query MongoDB with mongoose and return an array of string matching one of the keys of the schema

I have the following schema and would love to query my database for all products for example where the seller matches foo, and return only the categories in a string array. how do I achieve this using mongoose?
seller: {
type: String
},
category: {
type: String
},
price: {
type: String
},
}, {
timestamps: true
});
const Product = mongoose.model("Product", productsSchema);```
so I tested a few methods and I found this to work very well;
app.get("/shop", (req, res) => {
console.log(req.params.roomID);
Product.find({room: req.params.roomID}, (error, doc) => {
const categoryArray = doc.map(newArray => newArray.category);
You can use findOne function in the following form
const stringArray = await Product.find({seller:'foo'},{category:1});

Saving data to array in mongoose

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);

nodejs app mongoose database where clause with join

I have a schema article defined as:
var ArticleSchema = new Schema({
title: String,
content: String,
creator: {
type: Schema.ObjectId,
ref: 'User'
}
})
And user schema:
var UserSchema = new Schema({
type: String, //editor, admin, normal
username: String,
password: String,
})
I need to query all the article created by editor, i.e. in sql language
select Article.title as title, Article.content as content
from Article inner join User
on Article.creator = User._id
where User.type = 'editor'
This is what I have tried
exports.listArticle = function(req, res, next) {
var creatorType = req.query.creatorType
var criteria = {}
if (creatorType)
criteria = {'creator.type': creatorType}
Article.find(criteria).populate('creator').exec(function(err, articles) {
if (err)
return next(err)
//ok to send the array of mongoose model, will be stringified, each toJSON is called
return res.json(articles)
})
}
The returned articles is an empty array []
I also tried Article.populate('creator').find(criteria), also not working with error:
utils.populate: invalid path. Expected string. Got typeof `undefined`
There is no concept of joins in MongoDB, as it is a not a relational database.
The populate method is actually a feature of Mongoose and internally uses multiple queries to replace the referred field.
This will have to be done using a multi-part query, first on the User collection, then on the Article collection.
exports.listArticle = function(req, res, next) {
var creatorType = req.query.creatorType
var criteria = {}
if (creatorType)
criteria = {'type': creatorType}
User.distinct('_id', criteria, function (err, userIds) {
if (err) return next(err);
Article.find({creator: {$in: userIds}}).populate('creator').exec(function(err, articles) {
if (err)
return next(err)
//ok to send the array of mongoose model, will be stringified, each toJSON is called
return res.json(articles)
})
})
}

Resources