0

I am relatively new to nodejs. I am trying to save an image provided in a url (from api). After some online research, I decided to use createWriteStream method from nodejs to extract the image from url and save into the local directory. But I would like to be able to save directly to the mongodb. I am not able to figure out how to change the destination to a collection in mongodb.

My code snippet looks like below:

const fs = require('fs');
const request = require('request');
const Image = require('./models/Image');

const connectDB = require('./db');

connectDB();

const imageName = 'photo-' + Date.now();
const ext = 'jpg';


const url = 'https://some_path_for_image_by_api';

const getData = async (u, cb) => {
  const myImage = await request(url).pipe(
    fs.createWriteStream(`${imageName}.${ext}`)
  );
  cb(myImage);
};

const saveData = async (d) => {
  const image = await new Image(d);

  image.save(function (err, data) {
    if (err) return console.error(err);
    else return console.log('Image saved successfully', data);
  });
};

getData(url, saveData);

Here is my Image schema definition:

const mongoose = require('mongoose');

const ImageSchema = new mongoose.Schema({
  createdAt: {
    type: Date,
    default: Date.now,
  },
  img: {
    data: Buffer,
    contentType: String,
  },

module.exports = mongoose.model('Image', ImageSchema);

With this code, the image is saved from a url to my root directory in the folder (not desired). The image document is created but just with ObjectId and version, not actual data. The goal is to be able to save the image retrieved from a url directly to mongodb as a document while not saving anything to the root directory. Maybe I am not doing the right way. How do I save it to the db instead of being saved to some folders in the directory or to the root directory?Any help and suggestion will be much appreciated.

4
  • Does this answer your question? How to use GridFS to store images using Node.js and Mongoose Commented Oct 10, 2020 at 14:39
  • Can you share your Image model code? Commented Oct 10, 2020 at 17:34
  • @MattM, const mongoose = require('mongoose'); const ImageSchema = new mongoose.Schema({ createdAt: { type: Date, default: Date.now, }, }); module.exports = mongoose.model('Image', ImageSchema); Commented Oct 10, 2020 at 18:16
  • @KunalMukherjee, not quite. Thank you though. Commented Oct 10, 2020 at 18:19

1 Answer 1

0

Looks like the only field in your model is createdAt, so the image data itself wouldn't be saved. In order to save the image data, you'd need to add an appropriate field to the model.

From Mongoose docs:

The strict option, (enabled by default), ensures that values passed to our model constructor that were not specified in our schema do not get saved to the db.

https://mongoosejs.com/docs/guide.html#strict

Edit since posting schema: Try this.

const ImageSchema = new mongoose.Schema({
  createdAt: {
    type: Date,
    default: Date.now(),
  },
  img: {
    type: Buffer
  }
});

Then, you need to set that field by name in your model. Something like:

const image = new Image({ img: d });

where the field name is buffer.

I'm not familiar with fs so I can't help much there, but this assumes that d contains a byte array. If it's not currently a byte array, I think the next step would be converting it to one so it can be saved to MongoDB. This answer may help with that part:

https://stackoverflow.com/a/31217387/1520071

Sign up to request clarification or add additional context in comments.

8 Comments

Even if a add a field to the schema as { image: { type: Buffer } } How do I save to the db when I trigger the function? Currently, with just adding that field it is not saving that image to the db.
Can you update your code in your question so this change is reflected? Otherwise I can't be sure exactly what's happening. With the current code, you still need to set the field on the model to the image buffer. Not sure if you did that already. I'll update my answer to be more explicit about this.
Just updated the code with image schema and a little more clarification on the question
Nice, looks good. I think you need to change the model a bit still. Try img: Buffer. I'll update my answer again. Edit: I noticed your createdAt's default might've been set improperly due to missing parentheses. I added those to my suggestion too. That should at least fix createdAt not getting populated.
Getting this: { img: { CastError: Cast to Buffer failed for value "WriteStream { ......| messageFormat: undefined, kind: 'Buffer', value: [WriteStream], path: 'img', reason: null } }, _message: 'Image validation failed' }
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.