Home > database >  MongoDB relation between two collections by ID with the Express
MongoDB relation between two collections by ID with the Express

Time:05-19

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.

CodePudding user response:

AuthorID should be type ObjectId, not string.

To join data from other table, you have to use an aggregate with a lookup.

let author = await Author.aggregate([
    {
        $lookup:
        {
            from: "books",
            localField: "_id",
            foreignField: "authorID",
            as: "books"
        }
    }
]);

CodePudding user response:

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' });
  }
});
  • Related