I am making a blog system with multiple uploaded images, and multiple posts. I have created an upload screen which allows me to select a few of the previously images, and then posts that to the back end. This all works properly (thanks to some assistance I received at stack overflow), and the console gets this logged from the server:
[ 'http://res.cloudinary.com/jacobsiler-com/image/upload/v1574344215/SilerGuitars/f8q5d4kedss1tpmhxmwg.jpg',
'http://res.cloudinary.com/jacobsiler-com/image/upload/v1574344227/SilerGuitars/fveajqk0ehwy5mxywysa.jpg',
'http://res.cloudinary.com/jacobsiler-com/image/upload/v1574344201/SilerGuitars/lfxwkq8xhhkyxn85oyna.jpg' ]
These are image urls from images uploaded to Cloudinary and saved in a mongoDB document. Now I try to save this output to the selected post document with findOneAndUpdate:
app.post("/post-images", (req, res) => {
//const post=req
var postImages = req.body;
const postID = postImages.shift();
console.log(postImages);
Post.findByIdAndUpdate(
{ _id: postID },
{ $push: { imageUrls: { $each: [{ postImages }] } } },
{ lean: true, new: true },
function(err, foundPost) {
if (!err) {
console.log(foundPost);
res.redirect("/");
} else {
console.log("error: " + err);
}
}
);
//res.redirect("/");
});
I prepend what post ID I wish to add the images to the postImages array, then I separate it into my postID const and log the array of strings. It is the ID I chose. Then I try to push the string of an array of strings into the document. I can see that should probably only end up as one string in the document and I'm not sure how to handle this properly. I need to separate the saved urls somehow.
Here is my post DB in Robo 3T:
What I want is to end up with the highlighted object being one of the urls from the array, and all the other similar objects being one single url leading to an image.
I have tried using different update functions (updateOne, findByIdAndUpdate, findOneAndUpdate, etc.) with different options passed to them as well. It also seems that I have tried every concievable combination in this line:
{ $push: { imageUrls: { $each: [{ postImages }] } } }
All to no avail yet. Here are my Schemas and models:
//Defining the Image Schema
const imageSchema = {
url: String,
id: String
};
const Image = new mongoose.model("Image", imageSchema);
//Defining the Post Schema
const postSchema = {
title: String,
content: String,
imageUrls: [{ url: String }]
};
const Post = new mongoose.model("Post", postSchema);
I am not sure what I'm missing. All help and suggestions for getting this to work are greatly appreciated.
With trial, error, and trawling through mongoose documentation I eventually found the answer I was looking for. I hope the answer helps you out if you have the same problem.
First, I needed to change how I defined my schema because it wasn't meant to be an array of objects, but just an array:
//Defining the Post Schema
const postSchema = {
title: String,
content: String,
imageUrls: [ String ]
};
The former url and id field were unnecessary for my purposes so I removed them as well.
Then I looked in the mongoose documentation enough that I stumbled across $addToSet
and read about what it does. This seemed like the answer, and it turns out it is. To save my image urls to the document I ended up with this code:
app.post("/post-images", (req, res) => {
//const post=req
var postImages = req.body;
const postID = postImages.shift();
console.log(postImages);
Post.updateOne(
{ _id: postID },
{
$addToSet: { imageUrls: { $each: postImages } }
},
function(err, foundPost) {
if (!err) {
console.log(foundPost);
res.redirect("/");
} else {
console.log("error: " + err);
}
}
);
Now my code saved my array of urls properly, with each being a separate String under the imageUrls
Subdocument.