I have a controller edit card which updates the fields of cardsArray object.
cardsArray is mixed type object as fileds of each card object is different so i am storing mixed.type
Althought pushing new card using addCard controller works perfectly
But when edit card controller is called, it gives type error
When edit Controlller is callled is gives following error:
TypeError: Cannot read properties of null (reading 'cardsArray')
// Schema
const userSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
cardsArray: [{ type: mongoose.Schema.Types.Mixed }],
}
);
//__Mongodb Data
{
"_id": {
"$oid": "63b43ab32fc8d3c100cafecc"
},
"name": "usern_name",
"email": "pr****#gmail.com",
"password": "$2b$12$3nwifHakrBu94BwLXAC4Nu16Kw0.xyW8vAIPTMSgY7cYttVklDIZq",
"cardsArray": [
{
"title": "some_title",
"category": "Bank",
"cardHolder": "some_name",
"cardNumber": "54545454",
"expiry": "23/01",
"cvv": "***",
"logoIndex": 72,
"isFavourite": false,
"_id": {
"$oid": "63b83cc77288d277ef359533"
}
}
],
"loginIdsArray": [],
"docsArray": [],
"activitiesArray": [],
"__v": 0
}
// Add Card Controller.js___
addCard: async (req, res) => {
console.log(req.body.data, req.body.user_id)
// console.log('obj_id', newObjectId)
req.body.data._id = newObjectId;
try {
const response = await UserDatabase.findOneAndUpdate(
{ _id: req.body.user_id },
{
$push: {
// cardsArray: req.body.data,
cardsArray: { $each: [req.body.data] },
},
},
{ returnOriginal: false }
);
res.status(200).send(response);
} catch (error) {
console.log(error)
res.status(404).json({ message: error.message });
}
},
// edit card controller.js
editCard: async (req, res) => {
const id = req.params.id;
const { category, title, cardHolder, cardNumber, expiry, cvv, logoIndex, isFavourite } = req.body;
console.log(req.params.id)
try {
const response = await UserDatabase.findOneAndUpdate(
{ _id: "63b43ab32fc8d3c100cafecc", 'cardsArray._id': "63b709fc69a1cfa6fccd645c" },
{
$set: {
"cardsArray.$.title": req.body.title,
"cardsArray.$.category": req.body.category,
"cardsArray.$.cardHolder": req.body.cardHolder,
"cardsArray.$.cardNumber": req.body.cardNumber,
"cardsArray.$.expiry": req.body.expiry,
"cardsArray.$.cvv": req.body.cvv,
"cardsArray.$.logoIndex": req.body.logoIndex,
"cardsArray.$.isFavourite": req.body.isFavourite
}
},
);
console.log(response)
res.status(201).json(response.cardsArray);
} catch (error) {
console.log(error)
res.status(404).json({ message: error.message });
}
}
it means that there is no data matching the following _id and cardsArray._id
i thinks so its fails to find the feild 'cardsArray._id',first try finding the value by just findOne
await UserDatabase.findOneAndUpdate(
{ _id: "63b43ab32fc8d3c100cafecc", 'cardsArray._id': "63b709fc69a1cfa6fccd645c" })
if your find doesn't work try below methord not sure but it may work you have to either find the id and loop through the cardsArray of use $in or $match
await UserDatabase.findOneAndUpdate(
{ _id: "63b43ab32fc8d3c100cafecc", 'cardsArray':{$in:[ {_id:"63b709fc69a1cfa6fccd645c" }]})
I have and map structure stored at dynamodb, an I would like to add another attribute inside school object
something like:
{
name: 'Felipe'
uid: 112233,
data: {
structure: {
school: {
name: 'beta'
}
}
}
}
previously the add_year did not was a part of the structure, so this part is new
school: {
name: 'beta'
add_year: '2020'
}
How can I accomplised that?
I've tried the following solutions, without success
(async ()=>{
try {
let teste = await dynamoDb.updateItem({
TableName: 'test',
Key: {
uid: "112233"
},
UpdateExpression: "SET data.#structure.#school = list_append(#structure, :attrValue)",
ExpressionAttributeNames: {
"#data": "data",
"#structure": "structure",
"#school": "school",
},
ExpressionAttributeValues: {
":school":{
"add_year": 2020
}
},
ReturnValues:"UPDATED_NEW "
})
console.log('update',teste)
} catch (error) {
console.log(error)
}
Felipe, did you see the AWS documentation about this topic?
I think this code can work for you:
(async () => {
try {
var params = {
TableName: 'test',
Key: {
"uid": "112233"
},
UpdateExpression: "SET data.structure.school.add_year = :year)",
ExpressionAttributeValues: {
":add_year": 2020
},
ReturnValues: "UPDATED_NEW"
}
dynamoDb.update(params, (err, data) => {
if (err) {
console.error("Unable to update item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("UpdateItem succeeded:", JSON.stringify(data, null, 2));
}
})
} catch (error) {
console.log(error)
}
})
const { DocumentClient } = require('aws-sdk/clients/dynamodb');
const documentClient = new DocumentClient({
region: 'us-east-1',
});
try {
let add_year= '2020'
let teste = documentClient.update({
TableName: 'test',
Key: {
uid: "112233"
},
UpdateExpression: `SET #data.structure.school= :add_year`,
ExpressionAttributeValues: {
':add_year': add_year
},
ExpressionAttributeNames: {
"#data": "data"
},
ReturnValues:"ALL_NEW"
}).promise()
teste.then(t => console.log(t));
} catch (error) {
console.log(error)
}
In index.js, i create my database correctly, and i add a genre collection in the db, and is added fine.
However, when i add my rental collection, it isn't added or viewed in mongodb compass
My code for rental.js:
const mongoose = require('mongoose')
const joi = require('joi')
const rentalSchema = new mongoose.Schema({
customer: {
type: new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 2,
maxlength: 255
},
phone: {
type: String,
required: true,
minlength: 2,
maxlength: 255
},
isGold: {
type: Boolean,
default: false,
required: false
},
}),
movie: {
type: new mongoose.Schema({
title: {
type: String,
required: true,
trim: true,
minlength: 2,
maxlength: 500
},
dailyRentalRate: {
type: Number,
min: 2,
required: true,
max: 255
}
}),
},
dateOut: {
type: Date,
required: true,
default: Date.now
},
dateReturned: {
type: Date
},
rentalFee: {
type: Number,
min: 0
}
}
})
const Rental = mongoose.model('Rental', rentalSchema)
function validate(obj) {
const schema = {
customerId: joi.string().required(),
movieId: joi.string().required()
}
return joi.validate(obj, schema)
}
exports.Rental = Rental
exports.validate = validate
My index.js Code (Where i initialise the database):
const mongoose = require('mongoose')
const movies = require('./routes/movies')
const rentals = require('./routes/rentals')
mongoose.connect('mongodb://localhost/vidly', { useNewUrlParser: true})
.then(() => console.log('Connected to mongodb..'))
.catch(() => console.error('Error connecting...'))
This is unusual, as i do the same thing for genre, but it is added and viewed in mongodb compass!
[The image of mongo db compass is here: ]
Here is my rentals.js file, that uses rental.js for models:
const express = require('express')
const router = express.Router()
const {Customer} = require('../models/customer')
const Fawn = require('fawn')
const mongoose = require('mongoose')
const {Movie} = require('../models/movie')
const {Rental, validate} = require('../models/rental')
Fawn.init(mongoose)
router.get('/rentals', async (req, res) => {
const rentals = await Rental.find().sort('-dateOut')
res.send (rentals)
})
router.post('/rentals', async (req, res) => {
const {error} = validate(req.body)
if (error) return res.status(400).send('Error')
// Makes sure the customerId/customer sends us is valid
const customer = await Customer.findById(req.body.customerId)
if (!customer) return res.status(404).send('Invalid customerId')
const movie = await Movie.findById(req.body.movieId)
if (!movie) return res.status(404).send('Invalid movieId')
let rental = new Rental({
customer: {
_id: customer._id,
name: customer.name,
phone: customer.phone
},
movie: {
_id: movie._id,
title: movie.title,
dailyRentalRate: movie.dailyRentalRate
}
})
// This is for our success scenario
try {
// All args in here treated all together as unit
new Fawn.Task()
// First arg is collection we work with, and second is obj we wanna save
.save('rentals', rental)
// Update movies collection Second Arg is movie that should be updated Third is we increment the numInstock prop, and decrement by 1
.update('movies', { _id: movie._id}, {
$inc: { numberInStock: -1}
})
.run()
res.send(rental)
}
catch(ex) {
// 500 means Internal server error
res.status(500).send('Something failed.')
}
})
module.exports = router
Here is mongodb compass, and the collections seen
Using Fawn
The issue is one of usage with the Fawn library and comes from some misconceptions about the naming of mongoose models and how these interact with the library itself. As such the best way to demonstrate is with a minimal example of working code:
const { Schema } = mongoose = require('mongoose');
const Fawn = require('fawn');
const uri = 'mongodb://localhost:27017/fawndemo';
const opts = { useNewUrlParser: true };
// sensible defaults
mongoose.Promise = global.Promise;
mongoose.set('debug', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
// schema defs
const oneSchema = new Schema({
name: String
});
const twoSchema = new Schema({
counter: Number
});
// don't even need vars since we access model by name
mongoose.model('One', oneSchema);
mongoose.model('Two', twoSchema);
// log helper
const log = data => console.log(JSON.stringify(data, undefined, 2));
(async function() {
try {
const conn = await mongoose.connect(uri, opts);
// init fawm
Fawn.init(mongoose);
// Clean models
await Promise.all(
Object.entries(conn.models).map(([k,m]) => m.deleteMany())
)
// run test
let task = Fawn.Task();
let results = await task
.save('One', { name: 'Bill' })
.save('Two', { counter: 0 })
.update('Two', { }, { "$inc": { "counter": 1 } })
.run({ useMongoose: true });
log(results);
// List objects in models
for ( [k,m] of Object.entries(conn.models) ) {
let result = await m.find();
log(result);
}
} catch(e) {
console.error(e)
} finally {
mongoose.disconnect()
}
})()
Note how the mongoose models are registered here:
mongoose.model('One', oneSchema);
mongoose.model('Two', twoSchema);
That first argument is the registered name which mongoose uses for the model in it's internal logic. From the perspective of mongoose itself, once you have registered the model name with the schema as above, you can actually call an instance of the model as follows:
const One = mongoose.model('One');
Typically people export the result of the initial registration and then just use the returned value which is a reference to mongoose's own internal storage of the model details and attached schema. But the line of code is equivalent to that same thing as long as the registration code has already been run.
A typical exports considering this can therefore be used as:
require('./models/one');
require('./models/two');
let results = await mongoose.model('One').find();
So you might not see that often in other code examples, but that is really to show what is actually happening from the perspective of the Fawn library with later code.
With that knowledge you can consider the following code in the listing:
let task = Fawn.Task();
let results = await task
.save('One', { name: 'Bill' })
.save('Two', { counter: 0 })
.update('Two', { }, { "$inc": { "counter": 1 } })
.run({ useMongoose: true });
Here the methods of update() and save() familiar to mongoose and MongoDB users actually have a different first argument specific to their implementation on the Fawn.Task() result. That first argument is the "registered model name" for mongoose, which is what we just explained with the previous example.
What the Fawn library is actually doing is calling similar code to:
mongoose.model('One').save({ name: 'Bill' })
Well actually it's doing something a lot more complicated than that as is evidenced in the output of the example listing. It's actually doing a lot of other things related to two phase commits and writing temporary entries in another collection and eventually moving those over to the target collections. But when it does actually go to the collections for the registered models, then that is basically how it is doing it.
So the core issue in the code in the question is that you are not using the names that were actually registered to the mongoose models, and a few other things are missing from the documentation steps.
You're also not awaiting asynchronous functions correctly, and the try..catch within the question code is not doing anything with calls in this context. The listing here however demonstrates how to do that correctly using async/await.
You can alternately just use the native Promise.then(...).catch(...) aproach if your NodeJS version does not have async/await support, but there really is little other change than doing that and of course removing the try..catch since promises in that form will ignore it. Which is why you catch() instead.
NOTE - With some brief testing there appear to be a number of things which are supported mongoose/mongodb features which are not actually implemented and supported on this library's methods. Notably "upserts" was a prime example of a useful and common thing which the "two phase commit" system implemented here does not appear to support at all.
This partly seems an oversight in the code of the library where certain "options" to the methods are actually being ignored or stripped completely. This is a concern for getting the most out of MongoDB features.
Transactions
The whole usage of this library though at least seems suspicious to me that you picked it up because you "thought" this was "Transactions". Put plainly the two phase commit is NOT a transaction. Furthermore the implementation of any attempt at such control and rollback etc seem very loose at best.
If you have a modern MongoDB 4.0 server or above, and where you actually configured it to be named as a "replica set" ( which you can also do for a single member, where a common misconception is you need more than one ) then there is support for real transactions, and they are very easy to implement:
const { Schema } = mongoose = require('mongoose');
const uri = 'mongodb://localhost:27017/trandemo';
const opts = { useNewUrlParser: true };
// sensible defaults
mongoose.Promise = global.Promise;
mongoose.set('debug', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
// schema defs
const orderSchema = new Schema({
name: String
});
const orderItemsSchema = new Schema({
order: { type: Schema.Types.ObjectId, ref: 'Order' },
itemName: String,
price: Number
});
const Order = mongoose.model('Order', orderSchema);
const OrderItems = mongoose.model('OrderItems', orderItemsSchema);
// log helper
const log = data => console.log(JSON.stringify(data, undefined, 2));
// main
(async function() {
try {
const conn = await mongoose.connect(uri, opts);
// clean models
await Promise.all(
Object.entries(conn.models).map(([k,m]) => m.deleteMany())
)
let session = await conn.startSession();
session.startTransaction();
// Collections must exist in transactions
await Promise.all(
Object.entries(conn.models).map(([k,m]) => m.createCollection())
);
let [order] = await Order.create([{ name: 'Bill' }], { session });
let items = await OrderItems.insertMany(
[
{ order: order._id, itemName: 'Cheese', price: 1 },
{ order: order._id, itemName: 'Bread', price: 2 },
{ order: order._id, itemName: 'Milk', price: 3 }
],
{ session }
);
// update an item
let result1 = await OrderItems.updateOne(
{ order: order._id, itemName: 'Milk' },
{ $inc: { price: 1 } },
{ session }
);
log(result1);
// commit
await session.commitTransaction();
// start another
session.startTransaction();
// Update and abort
let result2 = await OrderItems.findOneAndUpdate(
{ order: order._id, itemName: 'Milk' },
{ $inc: { price: 1 } },
{ 'new': true, session }
);
log(result2);
await session.abortTransaction();
/*
* $lookup join - expect Milk to be price: 4
*
*/
let joined = await Order.aggregate([
{ '$match': { _id: order._id } },
{ '$lookup': {
'from': OrderItems.collection.name,
'foreignField': 'order',
'localField': '_id',
'as': 'orderitems'
}}
]);
log(joined);
} catch(e) {
console.error(e)
} finally {
mongoose.disconnect()
}
})()
That is really just a simple listing with the class Order and related OrderItems. There really is nothing special in the code and you should see that it's basically the same as most listing examples you will see with a few small changes.
Notably we initialize a session and also session.startTransaction() as an indicator that a transaction should be in progress. Note that session would generally have a wider scope where you would typically re-use that object for more than just a few operations.
Now you have session and the transaction is started, this is simply added to the "options" of the various statements being executed:
let [order] = await Order.create([{ name: 'Bill' }], { session });
let items = await OrderItems.insertMany(
[
{ order: order._id, itemName: 'Cheese', price: 1 },
{ order: order._id, itemName: 'Bread', price: 2 },
{ order: order._id, itemName: 'Milk', price: 3 }
],
{ session }
);
Admittedly this is a brief example that does not fully cover all write error possibilities and how to handle that within separate try..catch blocks. But as a very basic example should any error occur before the session.commitTransaction() is called, then none of the operations since the transaction was started will actually be persisted within the session.
Also there is "causal consistency" in that once a normal write acknowledgement has been confirmed, then within the scope of the session the data appears written to the respective collections right up until the transaction commit or rollback.
In the event of a rollback ( as demonstrated in the final operation ):
// Update and abort
let result2 = await OrderItems.findOneAndUpdate(
{ order: order._id, itemName: 'Milk' },
{ $inc: { price: 1 } },
{ 'new': true, session }
);
log(result2);
await session.abortTransaction();
These writes though reported to be made as seen in the operation result, are indeed "rolled back" and further operations see the state of the data before these changes were made.
The full example code demonstrates this by adding the items with another update action in one transaction, then beginning another to alter data and read it then abort the transaction. The final data state shows of course only what was actually committed.
NOTE Operations like find() and findOne() or anything that retrieves data must include the session whilst a transaction is active in order to see the current state, just in the same way that write operations are doing as shown in the listing.
Without including the session, these changes in state are not visible in the "global" scope until the transaction is resolved.
Listing Outputs
Code listings given produce the following output when run, for reference.
fawndemo
Mongoose: ones.deleteMany({}, {})
Mongoose: twos.deleteMany({}, {})
Mongoose: ojlinttaskcollections.deleteMany({}, {})
Mongoose: ojlinttaskcollections.insertOne({ _id: ObjectId("5bf765f7e5c71c5fae77030a"), steps: [ { dataStore: [], _id: ObjectId("5bf765f7e5c71c5fae77030d"), index: 0, type: 'save', state: 0, name: 'One', data: { name: 'Bill' } }, { dataStore: [], _id: ObjectId("5bf765f7e5c71c5fae77030c"), index: 1, type: 'save', state: 0, name: 'Two', data: { counter: 0 } }, { dataStore: [], _id: ObjectId("5bf765f7e5c71c5fae77030b"), index: 2, type: 'update', state: 0, name: 'Two', data: { '*_**ojlint**escape$*__tx__00***___string$inc': { counter: 1 } } } ], __v: 0 })
Mongoose: ojlinttaskcollections.updateOne({ _id: ObjectId("5bf765f7e5c71c5fae77030a") }, { '$set': { 'steps.0.state': 1 } })
Mongoose: ones.insertOne({ _id: ObjectId("5bf765f7e5c71c5fae77030e"), name: 'Bill', __v: 0 })
Mongoose: ojlinttaskcollections.updateOne({ _id: ObjectId("5bf765f7e5c71c5fae77030a") }, { '$set': { 'steps.0.state': 2 } })
Mongoose: ojlinttaskcollections.updateOne({ _id: ObjectId("5bf765f7e5c71c5fae77030a") }, { '$set': { 'steps.1.state': 1 } })
Mongoose: twos.insertOne({ _id: ObjectId("5bf765f7e5c71c5fae77030f"), counter: 0, __v: 0 })
Mongoose: ojlinttaskcollections.updateOne({ _id: ObjectId("5bf765f7e5c71c5fae77030a") }, { '$set': { 'steps.1.state': 2 } })
Mongoose: twos.find({})
Mongoose: ojlinttaskcollections.updateOne({ _id: ObjectId("5bf765f7e5c71c5fae77030a") }, { '$set': { 'steps.2.state': 1 } })
Mongoose: twos.update({}, { '$inc': { counter: 1 } }, {})
(node:24494) DeprecationWarning: collection.update is deprecated. Use updateOne, updateMany, or bulkWrite instead.
Mongoose: ojlinttaskcollections.updateOne({ _id: ObjectId("5bf765f7e5c71c5fae77030a") }, { '$set': { 'steps.2.state': 2 } })
Mongoose: ojlinttaskcollections.deleteOne({ _id: ObjectId("5bf765f7e5c71c5fae77030a") })
[
{
"_id": "5bf765f7e5c71c5fae77030e",
"name": "Bill",
"__v": 0
},
{
"_id": "5bf765f7e5c71c5fae77030f",
"counter": 0,
"__v": 0
},
{
"n": 1,
"nModified": 1,
"opTime": {
"ts": "6626877488230301707",
"t": 139
},
"electionId": "7fffffff000000000000008b",
"ok": 1,
"operationTime": "6626877488230301707",
"$clusterTime": {
"clusterTime": "6626877488230301707",
"signature": {
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"keyId": 0
}
}
}
]
Mongoose: ones.find({}, { projection: {} })
[
{
"_id": "5bf765f7e5c71c5fae77030e",
"name": "Bill",
"__v": 0
}
]
Mongoose: twos.find({}, { projection: {} })
[
{
"_id": "5bf765f7e5c71c5fae77030f",
"counter": 1,
"__v": 0
}
]
Mongoose: ojlinttaskcollections.find({}, { projection: {} })
[]
transdemo
Mongoose: orders.deleteMany({}, {})
Mongoose: orderitems.deleteMany({}, {})
Mongoose: orders.insertOne({ _id: ObjectId("5bf7661c3f60105fe48d076e"), name: 'Bill', __v: 0 }, { session: ClientSession("e146c6074bb046faa7b70ed787e1a334") })
Mongoose: orderitems.insertMany([ { _id: 5bf7661c3f60105fe48d076f, order: 5bf7661c3f60105fe48d076e, itemName: 'Cheese', price: 1, __v: 0 }, { _id: 5bf7661c3f60105fe48d0770, order: 5bf7661c3f60105fe48d076e, itemName: 'Bread', price: 2, __v: 0 }, { _id: 5bf7661c3f60105fe48d0771, order: 5bf7661c3f60105fe48d076e, itemName: 'Milk', price: 3, __v: 0 } ], { session: ClientSession("e146c6074bb046faa7b70ed787e1a334") })
Mongoose: orderitems.updateOne({ order: ObjectId("5bf7661c3f60105fe48d076e"), itemName: 'Milk' }, { '$inc': { price: 1 } }, { session: ClientSession("e146c6074bb046faa7b70ed787e1a334") })
{
"n": 1,
"nModified": 1,
"opTime": {
"ts": "6626877647144091652",
"t": 139
},
"electionId": "7fffffff000000000000008b",
"ok": 1,
"operationTime": "6626877647144091652",
"$clusterTime": {
"clusterTime": "6626877647144091652",
"signature": {
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"keyId": 0
}
}
}
Mongoose: orderitems.findOneAndUpdate({ order: ObjectId("5bf7661c3f60105fe48d076e"), itemName: 'Milk' }, { '$inc': { price: 1 } }, { session: ClientSession("e146c6074bb046faa7b70ed787e1a334"), upsert: false, remove: false, projection: {}, returnOriginal: false })
{
"_id": "5bf7661c3f60105fe48d0771",
"order": "5bf7661c3f60105fe48d076e",
"itemName": "Milk",
"price": 5,
"__v": 0
}
Mongoose: orders.aggregate([ { '$match': { _id: 5bf7661c3f60105fe48d076e } }, { '$lookup': { from: 'orderitems', foreignField: 'order', localField: '_id', as: 'orderitems' } } ], {})
[
{
"_id": "5bf7661c3f60105fe48d076e",
"name": "Bill",
"__v": 0,
"orderitems": [
{
"_id": "5bf7661c3f60105fe48d076f",
"order": "5bf7661c3f60105fe48d076e",
"itemName": "Cheese",
"price": 1,
"__v": 0
},
{
"_id": "5bf7661c3f60105fe48d0770",
"order": "5bf7661c3f60105fe48d076e",
"itemName": "Bread",
"price": 2,
"__v": 0
},
{
"_id": "5bf7661c3f60105fe48d0771",
"order": "5bf7661c3f60105fe48d076e",
"itemName": "Milk",
"price": 4,
"__v": 0
}
]
}
]
const { Rentals, validateRentals } = require("../models/rentals");
const { Movie } = require("../models/movie");
const { Customer } = require("../models/customer");
const Fawn = require("fawn");
const express = require("express");
const router = express.Router();
Fawn.init("mongodb://127.0.0.1:27017/vidly");
router.get("/", async (req, res) => {
const rentals = await Rentals.find().sort("-dateOut");
res.send(rentals);
});
router.get("/:id", async (req, res) => {
const rentals = await Rentals.findById(req.params.id);
if (!rentals)
return res.status(404).send("The rental with the given ID was not found.");
res.send(rentals);
});
router.delete("/:id", async (req, res) => {
const rentals = await Rentals.findByIdAndRemove(req.params.id);
if (!rentals)
return res.status(404).send("The rental with the given ID was not found.");
res.send(rentals);
});
router.post("/", async (req, res) => {
const { error } = validateRentals(req.body);
if (error) return res.status(400).send(error.detais[0].message);
const movie = await Movie.findById(req.body.movieId);
if (!movie)
return res.status(404).send("The rental with the given ID was not found.");
const customer = await Customer.findById(req.body.customerId);
if (!customer)
return res.status(404).send("The rental with the given ID was not found.");
if (movie.numberInStock === 0)
return res.status(400).send("Movie not in stock");
let rentals = new Rentals({
customer: {
_id: customer._id,
name: customer.name,
isGold: customer.isGold,
phone: customer.phone,
},
movie: {
_id: movie._id,
title: movie.title,
dailyRentalRate: movie.dailyRentalRate,
},
});
try {
new Fawn.Task()
.save("rentals", rentals)
.update("movies", { _id: movie._id }, { $inc: { numberInStock: -1 } })
.run();
res.send(rentals);
} catch (ex) {
res.status(500).send("Something failed");
}
// rentals = await rentals.save();
// movie.numberInStock--;
// movie.save();
// res.send(rentals);
//implementing transaction
});
router.put("/:id", async (req, res) => {
const { error } = validateRentals(req.body);
if (error) return res.status(400).send(error.detais[0].message);
const movie = await Movie.findById(req.body.movieId);
if (!movie)
return res.status(404).send("The rental with the given ID was not found.");
const customer = await Customer.findById(req.body.customerId);
if (!customer)
return res.status(404).send("The rental with the given ID was not found.");
let rentals = await Rentals.findByIdAndUpdate(
req.params.id,
{
customer: {
_id: customer._id,
name: customer.name,
isGold: customer.isGold,
phone: customer.phone,
},
movie: {
_id: movie._id,
title: movie.title,
dailyRentalRate: movie.dailyRentalRate,
},
},
{ new: true }
);
if (!rentals)
return res.status(404).send("The rentals with the given ID was not found.");
res.send(rentals);
});
module.exports = router;
Instead of using
Fawn.init(mongoose)
try using
Fawn.init('mongodb://localhost/yourDataBaseName')