MongoDB relation between two collections by ID with the Express

Issue

I am facing a problem while making a relation between two collections (I am using MEAN stack)
I have two collections: Books and Authors

In frontend I want to make a CRUD menu, where I add a new book in the table and then from there i insert a few data about book and then I choose author from the dropdown menu (fetchin data from Authors collection)

So at the end my Book collection needs to have a few data about the book and then inside the object i need an array of data about those author.

Book schema:

const BookSchema = new mongoose.Schema({
owner: { type: String, required: true },
pagesNo: { type: String, required: true },
releaseDate: { type: String, required: true }, 
country: { type: String, required: true },
authorID: { type: String, required: true }, <-- HERE I NEED DATA ABOUT AUTHOR
});

Author schema:

  const AuthorSchema = new mongoose.Schema({
      name: { type: String, required: true },
      surname: { type: String, required: true },
      dateOfBirth: { type: String, required: true },
      countryOfBirth: { type: String, required: true },
      
    });

Book route: book.ts

router.get("/", async (req, res) => {
  try {
    const books= await Book.find();

    let Author = await Author.find({
      books: { $elemMatch: { _id: books.bookID } },
    });

    res.status(200).json(books);
  } catch (err) {
    res.status(404).json({ success: false, msg: "Booknot found" });
  }
});

The problem is somewhere inside the find() function.. Is it even a good practice? I want that it can handle a lot of data.

Thanks to everyone!
Greetings.

Solution

Your Book schema would be like this:

const MongooseSchema = new mongoose.Schema({
  owner: {
    type: String,
    required: true,
  },
  pagesNo: {
    type: String,
    required: true,
  },
  releaseDate: {
    type: String,
    required: true,
  },
  country: {
    type: String,
    required: true,
  },
  authorId: {
    type: mongoose.Schema.ObjectId,
    ref: 'User',
    required: true,
  },
});

And your Author Schema would remain the same (in order to link both schemas).

Your route would be like this (if you want to search all books along with their author names):

router.get('/', async (req, res) => {
  try {
    const books = await Book.find().populate('authorId');

    res.status(200).json(books);
  } catch (err) {
    res.status(404).json({ success: false, msg: 'Booknot found' });
  }
});

And in case you want to search for books with a specific author id then your route would be like this:

router.get('/', async (req, res) => {
  try {
    const books = await Book.find({ authorId }).populate('authorId');

    res.status(200).json(books);
  } catch (err) {
    res.status(404).json({ success: false, msg: 'Booknot found' });
  }
});

Answered By – Daniyal Malik

Answer Checked By – Katrina (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.