2

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

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
Eesa Munir
  • 83
  • 9
  • `mongoose.connect('mongodb://localhost/vidly', { useNewUrlParser: true})` is invalid and would throw an error. You need to include the **port** with the `useNewUrlParser` option. `mongoose.connect('mongodb://localhost:27017/vidly', { useNewUrlParser: true})`. Right now these are "warnings", but expect that to become an actual error in the future. – Neil Lunn Nov 22 '18 at 21:21
  • Aside from that, you are likely not looking at your `vidly` database when in compass, or of course you are looking in `rental` when mongoose is actually using `rentals`. Which is going to be the presumed problem unless you can show otherwise. – Neil Lunn Nov 22 '18 at 21:24
  • It Still hasn't changed anything, as i tried adding port plus deleting the line completely. Same result though – Eesa Munir Nov 22 '18 at 21:24
  • I am 100% looking at the vidly db, but only one collection shows up which isn't the rental one but appears to have the exact same code. – Eesa Munir Nov 22 '18 at 21:25
  • Sorry lol, i have renamed all my models to unique ones, no errors, however still not appearing in mongodb compass – Eesa Munir Nov 22 '18 at 21:30
  • Since I don't see any data being inserted in the code of your question diagnosing is going to be a problem. Please read and follow [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) and include this minimal and reproducible example in your question showing data being inserted. Otherwise the only other possible issue are A. Wrong database B. Looking at wrong collections C. Bad code which is failing to do anything. And the "C" part is what is missing here. A schema alone tells us nothing. – Neil Lunn Nov 22 '18 at 21:36
  • Hey man, i have now edited my question please view. – Eesa Munir Nov 22 '18 at 21:44
  • Your model is named `'Rental'` and not `'rentals'`. The [fawn](https://www.npmjs.com/package/fawn) library you are using accesses the registered model name. You seem to be confusing this with the `const` you declared. Same for `movies` I presume since you did not include that model definition, but it's likely you called it `'Movie'` in just the same way. – Neil Lunn Nov 22 '18 at 21:51
  • So, do i change my model names to lowercase? e.g . const Rental = mongoose.model('rentals', rentalSchema) – Eesa Munir Nov 22 '18 at 21:55
  • Erm no. Change where you're accesing the models to use the registered names i.e `save('Rental', rental)` – Neil Lunn Nov 22 '18 at 21:56
  • Sorry neil man, this still hasn't solved my error, i changed to Rental + Movie instead of rentals and movis. Still no change – Eesa Munir Nov 22 '18 at 22:01
  • *"this still hasn't solved my error"* Yes it is. You even reposted the question without showing the code changed. Read the documentation link you were given and make the appropriate change. The fawn documentation clearly states the required argument is the registered model name with mongoose and you are using a different name. Twice even. – Neil Lunn Nov 23 '18 at 00:36
  • I had exactly the same problem. It was because I did not include the `.run()` at the end. As soon as I included it, the document was saved in the collections. Posting it here, just in case if it is helpful for future viewers of this question. – mukund Jan 14 '20 at 21:42

3 Answers3

2

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
      }
    ]
  }
]
Community
  • 1
  • 1
Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
  • Neil, I have renamed to the exact same name as registered. – Eesa Munir Nov 23 '18 at 17:06
  • @EesaMunir You have complete program listings and also included output as the result of "me running those programs". What you are expected to do is to use those same listings yourself in a fresh install and see them working for yourself. You can "compare" to your code to see what you are doing wrong. But we will not debug your entire project. You also have some really good advice here that you would "appear" to have chosen some library on the presumption it gave you "transactions". It does not, and you have instruction on how to do it correctly. I consider your question answered.Learn from it. – Neil Lunn Nov 23 '18 at 20:12
  • @EesaMunir Please stop sending comments. You can see they are being removed and I have said all that is needed to be said on the subject. You should run the code in the answer, see that it works and learn from it, [accept the answer](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) and move on. And most importantly **READ** the answer, because the point of this site is not about "getting code from people" but **learning** instead. – Neil Lunn Nov 24 '18 at 20:53
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;
  • Unblocking your blocker on Fawn. Take note of line 4 and 7. in my code. no need for you to require mongoose. you can ran Fawn directly with your db. view line 7. And as for the implementation check my router.post . don't forget to try and catch errors. Goodluck! – Olukayode Ifeoluwa Joshua Sep 13 '21 at 21:54
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-ask). – Community Sep 13 '21 at 23:22
0

Instead of using

Fawn.init(mongoose)

try using

Fawn.init('mongodb://localhost/yourDataBaseName')
rikyeah
  • 1,896
  • 4
  • 11
  • 21
  • Thank you for this code snippet, which might provide some limited, immediate help. A [proper explanation](https://meta.stackexchange.com/q/114762/349538) would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please [edit] your answer to add some explanation, including the assumptions you’ve made. – jasie Feb 10 '22 at 09:11