We have learnt to create most of features of an Ecommerce website. Still, we are missing one very major function of the web which is Image uploading. Any product should have Image to better identified and attract customers.

The basic process of our uploading Image feature are :

  1. Select the file path in user local machine
  2. Upload file using file picker of front end
  3. Send file to our api
  4. Multer middleware receive and filter file while also add file path to req
  5. Upload to Cloudinary using req.file.path
  6. Handle cloudinary response
  7. Add image link to mongoDB document

Cloudinary is a cloud service that offers a solution to a web application's entire image management pipeline.

Easily upload images to the cloud. Automatically perform smart image resizing, cropping and conversion without installing any complex software. Integrate Facebook or Twitter profile image extraction in a snap, in any dimension and style to match your website's graphics requirements. Images are seamlessly delivered through a fast CDN, and much much more.

For Node.js, Cloudinary provides an extension for simplifying the integration even further.

Set up Cloudinary

Sign Up an Account

login

dashboard

npm install cloudinary

We are ready to start using cloudinary

About Multer

Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files. .

NOTE: Multer will not process any form which is not multipart (multipart/form-data).

Multer adds a body object and a file or files object to the request object. The body object contains the values of the text fields of the form, the file or files object contains the files uploaded via the form.

Multer configuration snippet

Since the client could send any files to our server, we will need to filter out any files that not images. To do that, we will use file.extname : extention as an indicator of file type.

const multer = require("multer");
const path = require("path");

module.exports=multer({
  storage:multer.diskStorage({})
  fileFilter:(req,file,cb)=>{
    let ext=path.extname(file.originalName)
    if(ext !==".jpg"&&ext!==".jpeg"&&ext!=="png"){
      cb(new Error("File extension not supported"),false)
      return
    }
    cb(null,true)
  }
})

What isfaker? faker is a JavaScript tool that helps generate realistic fake data for your applications. Their documentations are lacking so we will go over some common situations you may run into in this lecture, from very simple to moderately complex.

1. Install faker.js

First, install faker in your backend project:

npm install faker

Create a new file called generateData.js in the root of your project. We will run this file independently of the backend when we want to generate data.

In this file, import faker:

const faker = require('faker');

2. Get a Random Number

API Documentation: faker.random.number()

Instead of writing our own function to generate a random number from a predefined range with Math.random(), faker has its own function that we can utilize.

Let's write a function to generate a random number from 0 and 10. We will use the namespace random from faker, and we want a number, so we will use faker.random.number():

const getRandomNumber = () => {
const num = faker.random.number(10)
}

The default min is 0 and this .number() method takes a number argument as the max value. You can also pass an object with min and max here.

For example, if you want a random number between 22 and 50, you can do:

const num = faker.random.number(28) + 22;

or

const num = faker.random.number({min: 22, max: 50})

3. Get a Random Element in an Array

API Documentation: faker.random.arrayElement()

Previously, in order to get a random item in an array, we needed to do something like:

const arr = ["apple", "watermelon", "peach"];
const randomIndex = Math.floor(Math.random()*arr.length);
const randomElement = arr[randomIndex];

If you want more than 1 item, it will be even more complicated. Now faker has something similar already which can save you a lot of time if you have many arrays to work with.

faker.random.arrayElement(array): For this, we need to pass an array to this function. It will return a random item in that array.

const arr = ["apple", "watermelon", "peach"];
const randomElement = faker.random.arrayElement(arr);

faker.random.arrayElements(array, num): This function will return multiple non-repeating items inside an array. Therefore we need to pass the array itself and a number which represents how many items we want back from this array.

const arr = ["apple", "watermelon", "peach"];
const randomElement = faker.random.arrayElements(arr, 2);
// this will return 2 random items in the array arr

4. Generate Lorem Ipsum Text

API Documentations: faker.lorem.words() & faker.lorem.paragraphs()

We mostly use these methods to generate gibberish long texts. For example, for product reviews, product details, blog posts, post titles, About Us text, etc.

faker.lorem.words(number): We pass in a number to generate that exact number of random lorem words.

const randomWords = faker.lorem.words(3);
// example result: iure quos aut

faker.lorem.paragraphs(number): We pass in a number to generate a number of paragraphs.

const randomParagraphs = faker.lorem.paragraphs(3);
/** example result:
Dolorem excepturi aut id esse neque. Voluptate corrupti ducimus fuga fugit. Itaque ex libero rerum porro. Reprehenderit omnis quis dolorum numquam quia ducimus est molestias. Sed non et voluptas explicabo iure voluptatem. Aut minus ut dolorem unde.
Ipsa molestiae enim neque culpa sit corporis cum. In odio aut. Est aperiam facere esse itaque omnis. Et alias doloribus.
**/

5. Generate User Data

API Documentations: faker.name.findName() & faker.internet.email(http://marak.github.io/faker.js/faker.internet.html#.email__anchor)

We will use various faker namespaces to generate a semi-complete user profile data. Let's go over the most basic user information.

Name:

We can use faker.name.findName() to generate a full name (that may include a title). You can also customize it further to return a female name or a male name, or a fixed first name or last name. The function has 3 optional parameters: first name, last name and gender.

const randomName1 = faker.name.findName();
//will return a random full name

const randomName2 = faker.name.findName('', '', 0);
// will return a random male name (0 = male, 1 = female)
// will possibly return something like Ms. Luke Klein even though gender = male because the title is not considered

If your user schema has a gender field and you want the name to match this field, you may need to combine several different faker functions together:

const gender = 0; //male
const firstName = faker.name.firstName(gender);
const lastName = faker.name.lastName();
const fullName = firstName + " " + lastName;

Email:

We can use faker.internet.email() to get a completely random email, or we can pass firstName and/or lastName as an argument to this to get a more personal email:

const gender = faker.random.number(1); //male or female
const firstName = faker.name.firstName(gender);
const lastName = faker.name.lastName();
const fullName = firstName + ' ' + lastName;
const email = faker.internet.email(firstName, lastName);
console.log(fullName);
console.log(email);
// example result
//Edward Volkman
//Edward_Volkman@gmail.com

You can also generate an address, a date of birth (faker.date.betweens), etc. Just experiment with some of the namespaces until you're familiar with faker.

6. Generate a Complete Product

API Documentations: faker.commerce

Let's say you need a name, a description, some categories and a price for your product. We can't really use a person's name for the product's name. Furthermore, while a lorem ipsum text would work for the description, faker provides something better with its commerce namespace.

faker.commerce.productName(): As the name suggests, this will return a product-eque name. The name may sound funny or ridiculous, but that's okay because we're not trying to pass this as a real product.

const randomName = faker.commerce.productName();
// example result: Incredible Rubber Computer

faker.commerce.productDescription(): Will return some nonsensical description, which is better than a lorem ipsum text, but if you want control over the length of the description, then faker.lorem is the better choice.

const randomDesc = faker.commerce.productDescription();
// example result:
// The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality

faker.commerce.department(): This is to generate the category for your product. If you want multiple categories, simply run it in a for loop.

const category = faker.commerce.department();
// example result: Beauty

faker also has a price function, but if you're working with VND where the smallest denomination is 500 (or 1000 in reality), then it doesn't make sense to generate a number like 529163. You can use a trick for this with the normal faker.random.number().

const randomPrice = faker.random.number({min: 50, max: 3000}) * 1000;
// price ranging from 50000 to 3000000

Combine all of this together, you can have a nice looking product object:

{
name: "Incredible Rubber Computer",
description: "The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality",
categories: ["Beauty", "Home"]
price: 630000,
}

faker has an image namespace as well, but it's not good, so let's ignore it for now.

Now that we can generate some data in Node.JS, we need to actually get this data onto our database. Just like with your backend project, we can connect to our MongoDB in Node.JS using mongoose:

require('dotenv').config();
const mongoose = require('mongoose');
const mongoURI = process.env.MONGODB_URI;

mongoose
	.connect(mongoURI, {
		// some options to deal with deprecated warning
		useCreateIndex: true,
		useNewUrlParser: true,
		useFindAndModify: false,
		useUnifiedTopology: true,
	})
	.then(() => {
		console.log(`Mongoose connected to ${mongoURI}`);
	})
	.catch((err) => console.log(err));

Then let's create an async function to generate 20 users. We're going to need to import our User schema before we can do anything with MongoDB.

const User = require('./models/User');

//...

const generateUser = async (num) => {
    for (let i = 0; i < num; i++) {
        const user = await User.create({
        name: faker.name.findName(),
        email: faker.internet.email(),
        // you may need to hash this password first
        password: "123",
        });
        console.log(`User ${i+1} ${user.name} created!`)
    }
}

Now run it at the bottom:

generateUser(10);

You should see the results in both your terminal and your MongoDB database. You can apply a similar logic to create data for Product, Comment,Rating, Cart (transactions), and more. Of course it won't be this simple, but with practice, you'll figure out how to handle the relationships between these models.

Since the image generator of faker is frustratingly lackluster, we need to rely on an extra service to handle generating random images. Unsplash is one of them. However, their random image API (and their database) will return artistic, scenic images while what we need are product images. Therefore we will need to find the images that fit your theme yourself.

If you have download enough of them I don't want to manually upload them to Cloudinary, write down the URLs and save them to your database, then you can automate this process with the help of Cloudinary Upload API and faker.

1. Getting Started

You can find the documentation here.

npm install cloudinary
 cloudinary = require('cloudinary').v2;
cloudinary.config({
  cloud_name: 'YOUR_CLOUD_NAME',
  api_key: 'YOUR_API_KEY',
  api_secret: 'YOUR_API_SECRET'
});
cloudinary.uploader.upload("YOUR_LOCAL_IMAGE_PATH", function(error, result) {console.log(result, error)});

This is a single file update. should we repeat this every time we want to generate image data?

2. Read File Names in a Folder

We can't possibly do the previous step over and over again for every single image we have. That would not be different from manually uploading the images using Cloudinary widget.

That's why we need to put all the images we want to upload in a folder, and get all of the image file's names and put them in an array, then we can loop through the array and upload them, or upload random elements of the array.

let images = fs.readdirSync('./images');

//console.log() it to be sure
console.log(images)

3. Automate the Upload Process

Whenever you create a new product, you need to get a random file name from this images array, then upload that file to Cloudinary and save the URL in the response to your database.

const generateProduct = async (num) => {
    for (let i = 0; i < num; i++) {

        const product = await Product.create({
        name: faker.commerce.productName(),
        price: faker.random.number({min: 50, max: 3000}) * 1000,
        images: [image]
        });
        console.log(`User ${i+1} ${product.name} created!`)
    }
}

Combining this with the previous steps, you should be able to upload random images and attach the response's links to your products, then save them in your database.