negladiator
negladiator

Reputation: 21

How do I update MongoDB database, using Express JS and Mongoose with PUT method?

I am currently running MongoDB locally version 3.2.3. Current Node Server version 7.2.0. The API was written in Typescript.

List of relevant dependencies:

"dependencies": {
    "@types/mongoose": "^4.7.3",
    "@types/node": "^6.0.56",
    "bcrypt-nodejs": "0.0.3",
    "body-parser": "^1.15.2",
    "compression": "^1.6.2",
    "dotenv": "^4.0.0",
    "ejs": "^2.5.5",
    "express": "^4.14.0",
    "mongodb": "^2.2.21",
    "mongoose": "^4.7.6",
    "path": "^0.12.7"
  }

My server.js file relevant statements:

// Modules extending node
import * as express from 'express';
import * as bodyParser from 'body-parser';
import * as http from 'http';
import * as path from 'path';

// Custom modules imported.  Some are routers behaving as miniapps routed to the main app.
import { digitalAssetRouter } from './api/digitalMedia/digitalmediaController';

/**
 * Node Express Server Controller
 */

let app = express();

app.use((req, res, next)=>{
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3050');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views/'));
let server = http.createServer(app);

//Configure express
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use((err, req, res, next) =>
    res.status(500).send(JSON.stringify({ err: 'Bad API Request!' }))
);

//Route
app.use('/', indexRouter);
//API Routes

// API Information
app.use('/api/v1', digitalAssetRouter);

// Digital Assets
//GET ALL AND POST CREATE ONE
    app.use('/api/v1/digitalassets', digitalAssetRouter); 
//GET ONE BY ID, PUT ONE BY ID, DELETE ONE BY ID
    app.use('/api/v1/digitalassets/:digitalassetsId', digitalAssetRouter);
//UPDATE BY ID I TRIED BOTH WAYS, ABOVE AND BELOW
    app.use('/api/v1/digitalassets/update/:digitalassetsId',      digitalAssetRouter);

// catch 404 and forward to error handler
app.use((req, res, next) => {
    let err = new Error('Not Found');
    err.message = '404';
    next(err);
});

// error handler
app.use((err, req, res, next) => {
    // set locals, only providing error in development
    res.locals.message = err.message;
    res.locals.error = req.app.get('env') === 'development' ? err : {};

    // render the error page
    res.status(err.status || 500);
    res.render('error');
});


//server start
server.listen(3000, () => {
    console.log('LOCALHOST Running @ port 3000');
    console.log(app.get('env'));
});

//Expose server module
export { app };

Below is my controller relevant methods:

/**
 * Digital Media Controller Module
 */

import * as express from 'express';
import { digitalAsset } from './digitalmediaModel';

//Creates a mini app that only handles routes for digital assets
let digitalAssetRouter = express.Router();

/**
 * UPDATE ONE BY ID
 * Patch attributes for a model instance and persist it into the data source.
 */
digitalAssetRouter.put('/digitalassets/:digitalassetsId', (req, res, next) => {
    console.log(req.params);
    console.log(req.body);
    digitalAsset.findByIdAndUpdate(req.params.digitalassetsId, req.body)
        .then(response => {
            res.status(200).json({
                comment: 'Patch attributes for a model instance and persist it into the data source.',
                responseType: 'success'
            });
        })
        .catch(err => {
            // console.log(err);
            res.status(400).json({
                error: "Cannot find digital image with id: " + req.params.digitalassetsId,
                errorMessage: err
            });
        });
});

I read the documentation directly from mongoose regarding findByIdAndUpdate. I have made several attempts to modify the way I send data to update via postman.

Postman PUT method to api endpoint to update by id I also put Content-Type is application/json in headers. The payload being sent was raw data in JSON format shown below. This is what appears in console.log(req.body):

{
    "altText" : "Canon alt text"
}

Below is my model of a digitalasset:

/**
 * Digital Media Model
 */
import { mongooseDb } from '../../config/db';
mongooseDb.Promise = global.Promise;

let Schema = mongooseDb.Schema;
let TagsSchema = new Schema({
    id: String,
    name: String,
    app_id: String,
    value: Number
},
    { _id: false });

let ExifSchema = new Schema({
    make: String,
    model: String,
    width: Number,
    length: Number,
    created: String,
    fileSource: String,
    exposureMode: String,
    exposureTime: String,
    aperture: Number,
    iso: Number,
    exposureBias: Number,
    flash: String,
    orientation: String
},
    { _id: false });

let DigitalAssetSchema = new Schema({
    fileName: String,
    title: String,
    caption: String,
    altText: String,
    description: String,
    fileType: String,
    uploadedOn: {
        type: Date,
        default: Date.now,
    },
    uploadedBy: String,
    fileSize: {
        type: Number,
    },
    url: {
        type: String
    },
    relativePath: String,
    categories: [String],
    tags: [TagsSchema],
    exif: ExifSchema,
    embedUrl: String,
    shareUrl: String
});

let digitalAsset = mongooseDb.model('digitalAsset', DigitalAssetSchema);

export { digitalAsset };

I have no problem creating documents in the database and deleting them. When it comes to updating them via PUT method using express routing, the process is not working. I have tried different variations just to change one field in the document chosen with no success. I provide examples below of screenshots in Postman:

I have some records in MongoDB to update as follows.

{
    "_id" : "589739a960aa6d23823cafb9",
    "altText" : "CHANGE",
    "description" : "CHANGE",
    "relativePath" : "assets/Pics/high resolution/purchasable pictures/various.corbis/Internet/42-17083495.jpg",
    "fileName" : "/disk/assets/Pics/high resolution/purchasable pictures/various.corbis/Internet/42-17083495",
    "fileSize" : 8220,
    "title" : "CHANGE",
    "fileType" : ".jpg",
    "caption" : "CHANGE",
    "uploadedBy" : "rmore071",
    "__v" : 0,
    "tags" : [ 
        {
            "name" : "people",
            "value" : 0.98049
        }, 
        {
            "name" : "outdoors",
            "value" : 0.9785451
        }, 
        {
            "name" : "architecture",
            "value" : 0.95540833
        }, 
        {
            "name" : "horizontal plane",
            "value" : 0.955212
        }, 
        {
            "name" : "travel",
            "value" : 0.95194626
        }, 
        {
            "name" : "industry",
            "value" : 0.9321301
        }, 
        {
            "name" : "flame",
            "value" : 0.9265379
        }, 
        {
            "name" : "man",
            "value" : 0.9220996
        }, 
        {
            "name" : "business",
            "value" : 0.91815794
        }, 
        {
            "name" : "heat",
            "value" : 0.89368707
        }, 
        {
            "name" : "no person",
            "value" : 0.89319044
        }, 
        {
            "name" : "panoramic",
            "value" : 0.8734973
        }, 
        {
            "name" : "illuminated",
            "value" : 0.8665502
        }, 
        {
            "name" : "adult",
            "value" : 0.86405236
        }, 
        {
            "name" : "fossil fuel",
            "value" : 0.8607676
        }, 
        {
            "name" : "transportation system",
            "value" : 0.8506778
        }, 
        {
            "name" : "competition",
            "value" : 0.83268094
        }, 
        {
            "name" : "building",
            "value" : 0.8307033
        }, 
        {
            "name" : "action",
            "value" : 0.8292489
        }, 
        {
            "name" : "horizontal",
            "value" : 0.829162
        }
    ],
    "categories" : [],
    "uploadedOn" : "2017-02-05T14:41:45.984Z"
}

When I hit send in Postman I get:

{
  "comment": "Patch attributes for a model instance and persist it into the data source.",
  "responseType": "success"
}

This tells me that the promise did not return an error and printed out the contents in the then() function since the id was accepted.

However with a quick look in the database using RoboMongo, I see the field altText has not been updated.

My question is exactly as titled, How do I update with PUT method? I am doing something wrong, and would really like another pair of eyes to glance over and see what I did wrong. Thank you in advanced for your time.

Upvotes: 0

Views: 4791

Answers (1)

negladiator
negladiator

Reputation: 21

It turns out that as a value for my _id key is a string in the database. When I turned on mongoose debugging, explained here, I noticed that mongoose was sending: Mongoose: digitalassets.findOne({ _id: ObjectId("58969de160aa6d23823c9e69") }, { fields: undefined }), and the value in the database was string. So the response would be null because the query did not find a value ObjectId("58969de160aa6d23823c9e69"). I corrected the issue by updating the values for the _id keys from strings to Objects, i.e. ObjectId("58969de160aa6d23823c9e69").

I suspect when I created a local development database environment and copied a subset of documents from my live database to the development database, ObjectId values were changed to strings, causing the issue of getting null responses from Mongoose's method findByIdAndUpdate(), executed in a PUT express route.

Upvotes: 2

Related Questions