How to prevent mongoose from inserting with ObjectID instead of embedding it

Viewed 155

I got a two MongoDB collections like below, (a library only has one book for demonstration purposes):

// books
| _id             | author | title |
| ObjectID("yyy") | jean   | foo   |
| ObjectID("yyy") | paul   | bar   |
| ObjectID("yyy") | baz    | boo   |

// library
| _id             | name   | book            |
| ObjectID("xxx") | foobar | ObjectID("yyy") |
| ObjectID("xxx") | pagez  | ObjectID("yyy") |
| ObjectID("xxx") | booky  | ObjectID("yyy") |

I made a schema for a library like this

export const LibrarySchema = new Schema({
  name: {
    type: String,
    required: true,
  },
  book: {
    _id: false,
    type: Schema.Types.ObjectId, // (1)
    ref: "Book" // yes, the schema is registered properly, it's called `Book`
  }
})

(1) I have the ObjectID since (as shown in the collection) the book is stored with an objectid reference, if I change them to the book schema it won't find them anymore while populating.

Now, the problem comes here, my goal is to have a raw collection which embeds all the libraries and their book, like below:

// library_complete
| _id          | name   | book                            |
| ObjId("xxx") | foobar | { author: "jean", title: "foo"} |
| ObjId("xxx") | booky  | { author: "baz", title: "boo"}  |

(Please don't ask why I need a raw (embedded) collection, I've replicated my goal to be as easily understandable as possible and it's absolutely necessary to have a raw (embedded) collection)

The schema for the raw libary collection is like this:

const RawLibrarySchema = new Schema({
  name: {
    type: String,
    required: true
  },
  book: {
    _id: false,
    type: BookSchema, // changing this to `Object` doesn't work either
  }
})

Now, in the service when I want to create a book

const linkLibaryToBook = async (library, bookId) => {
  // some complex calculations to link library to books and populates it
  const libraryBook = await someComplexFunction(library, bookId); // in this function the book gets populated, see the return type below
  console.log(libraryBook);
  /* @returns
  libraryBook {
    name: "foobar",
    book: { author: "jean", title: "foo" },
  }
  */
  saveRawLibrary(libraryBook);
}

The above return type is exactly what I want to achieve, now when I write that away like below

const saveRawLibrary = async (libraryObject) => {
  console.log(libraryObject);
  /* @returns
  libraryBook {
    name: "foobar",
    book: { author: "jean", title: "foo" },
  }
  // ^ this is as it should be ^
  */
  const _library = new libraryModel(libraryObject);
  console.log(_library);
  /* @returns
  _library {
    name: "foobar",
    book: "9023920dada032aa" // the objectId of the original book
  }
  // ^ this is what comes out ^
  */
}

all of a sudden mongoose has linked the ID of the book to the library instead of the object. I just want to write the plain object away like shown in the first two console logs. I've also tried using a plain create like this:

const saveRawLibrary = async (libraryObject) => {
  await libraryModel.create(libraryObject);
}

However, that does the exact same, it just references it with id... is there a way to just plain insert an object? If you want to see the real object and result you can click here.

TL;DR; I have a JavaScript object which I want to write away, but if I do that, it magically assigns objectIDs instead of the original object.

1 Answers

Try this way.

const mongoose = require('mongoose');

const bookSchema = new mongoose.Schema({
    title: String,
    author: String,
    library: {
      type: mongoose.Types.ObjectId,
      ref: 'library'
    },
  })

const librarySchema = new mongoose.Schema({
    name: String,
    book: {
      type: mongoose.Types.ObjectId,
      ref: 'book'
    }
});

const Book = mongoose.model('Book', bookSchema);
const Library = mongoose.model('Library',librarySchema);

const book1 = new Book({
    _id: new mongoose.Types.ObjectId(),
    author: 'Ian Fleming',
    title: 'Casino Royale',
});

console.log(book1);

book1.save(function (err) {
    if (err) return handleError(err);
});

const library1 = new Library({
    name: 'AMsterdaam',
    book: book1._id    // assign the _id from the book
});

library1.save(function (err) {
    if (err) return handleError(err);
  });

 console.log(library1); 

Output

{
  _id: 5f6f2d7e734c4e285e399460,
  author: 'Ian Fleming',
  title: 'Casino Royale'
}
{
  _id: 5f6f2d7e734c4e285e399462,
  name: 'AMsterdaam',
  book: 5f6f2d7e734c4e285e399460
}
Related