I am using mongoose
and express
to create my database and server respectively.
I have a Schema like below for my data:
const mongoose = require('mongoose')
const {Schema} = mongoose
const quotesSchema = new Schema({
tags: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Tags' // I want to save an array of tags coming in from the request body
}
],
content: {
type: String,
required: true
},
author: {
type: String,
required: true
},
authorSlug: {
type: String,
},
dateAdded: {
type: Date,
default: Date.now()
},
dateModified: {
type: Date,
default: Date.now()
},
})
const Quotes = new mongoose.model('Quotes', quotesSchema)
module.exports = Quotes
I want to save an array of tags coming in from the request body but it only saves one item from the array.
Here's my sample code:
router.post('/', async (req, res, next) => {
try {
const {tags, author, content} = req.body
const slug = author.replace(/\s /g, '-').toLowerCase()
var tagIds = []
tags.forEach( async (tag) => {
const foundTag = await Tag.find({name: tag}) // I first of all search my tag collection
// to see if the names supplied in the request body tags array exist,
// then try to extract their Objectids and store in an array to move to the next step - saving the quote
// foundTag.forEach(async (item) => {
// return await tagIds.push(item._id)
// })
for (var i = 0; i < foundTag.length; i ) {
tagIds.push[i]
}
console.log(tagIds)
const quote = new Quote({
tags: tagIds,
content,
author,
authorSlug: slug
})
const quoteToSave = await quote.save()
return res.status(201).json({
success: true,
msg: 'Quote Created Successfully',
quote: quoteToSave
})
})
} catch (error) {
console.error(error)
}
})
How do I pass the complete array of tags as a parameter to my quote to save. I think the issue here is that it doesn't wait for the second tag to enter the array.
Here's an image of my request-response in Postman:
How do I get the tags which is an array from req.body
and save it as part of my quote object? At the moment I am doing everything inside my forEach
loop and it doesn't seem decent enough to me. Is there a best approach like wait for the data then the save part will not have any parent control statement, like currently.
Thanks
CodePudding user response:
#1 If you will use async functions
inside forEach
then use Promise.all()
with bluebird
.
#2 MongoDB operators
are very useful.
#3 Knowing the difference between forEach
and map
is very important.
#4 express response doesn't need return
statement if you use it correctly.
The final code will look something like:
router.post('/', async (req, res, next) => {
const { tags, author, content } = req.body
const slug = author.replace(/\s /g, '-').toLowerCase()
var foundTags = await Tag.find({ name: { $in: tags } })
if (foundTags) {
var tagsIds = []
foundTags.map(tag => {
tagsIds.push(tag._id);
})
const quote = new Quote({
tags: tagsIds,
content,
author,
authorSlug: slug
})
const quoteToSave = await quote.save()
if (quoteToSave) {
res.status(201).json({
success: true,
msg: 'Quote Created Successfully',
quote: quoteToSave
})
} else {
res.status(500).json("failed saving quote")
}
} else {
res.status(500).json("failed finding tags")
}
})