MongoDB Datastore

Demo Project Model Details

🙋 Need help? Ask an expert now!

User Model

src/db-models/user-model.js. The Schema contains several basic demo fields. Here's an example of defining a field as required and supplying a default value to it:

    primary_locale: {
      type: String,
      default: 'en',
      required: true
    }

Technically, if the default is specified, mongoose will add the field with that value in it, so including both properties is redundant, unless we want to stress the importance of the field and (hypothetically) cover update-time validations by mongoose on Documents inserted by external systems.

The Model statement links the Schema to the MongoDB Collection named user:

export default mongoose.model('User', UserSchema, 'user');

Item Model

src/db-models/item-model.js. The Schema illustrates the use of a free-form embedded object:

    item_details: {
      type: Object,
      default: {}
    },

This indicates that any multi-property object can be placed into the item_details field of the Item document, and if one is not provided - mongoose will create an empty document placeholder in that field.

A more controlled way of embedding an Object is seen here:

    item_price: {
      type: [ItemPrice],
      required: true
    }

ItemPrice is a Schema defined in another file (src/db-models/item-price-model.js) and imported at the top of the src/db-models/item-price-model.js. The [] indicate that item_price is an array of ItemPrice objects - from the business Use Case standpoint, there may be multiple prices defined for an Item, e.g. by dates or discount type, etc.

Item Price Model (Schema only)

src/db-models/item-price-model.js. Note that export default statement exports a Schema vs. a Model as ItemPrice is an object designed to be embedded into another Document vs. being a Collection Document by itself.

_id: false signals mongoose to skip ID generation for the embedded ItemPrice object. Per the Schema, modification timestamps on the ItemPrice embedded object will be maintained.

User Order Model

src/db-models/user-order-model.js. In the demo project design, Orders and Order Items are stored in one MongoDB Collection named user_order.

Each Document contains IDs of the User (user_id) and Payer (payer_id). Think of the User as Sold-to and Ship-to, and Payer as Bill-to.

Users and Payers would be stored in the user Collection described via the User Model. The ref: 'User' field in this schema enables functionality of mongoose-proprietary lookup engine Populate. However, in the demo project, mongoose Populate is not utilized as we're limiting dependencies on proprietary features, so the ref property is included for information only.

Both user_id and payer_id have single field indexes created, which assist finding all Orders by the given User or paid for by the User-Payer. There are also two Compound indexes as mentioned earlier.

Order Date will be maintained transparently (see "Date and Time" in "MongoDB Schema Design Considerations") as we specify the Date type in the Schema:

    order_date: {
      type: Date
    },

The Order Items is an embedded array of Objects defined the OrderItemSchema, imported from src/db-models/order-item-model.js:

    order_items: {
      type: [OrderItemSchema]
    }

Order Item Model (Schema Only)

src/db-models/order-item-model.js. Similarly to the Item Price, Order Item is a Schema-only in our design, with no corresponding Model (Collection).

A designated unique _id is added to each embedded Order Item object, the default MongoDB ObjectId type is used:

    _id: {
      type: mongoose.Schema.Types.ObjectId,
      auto: true,
      index: true
    },

The auto flag ensures that the _id is generated by mongoose. By default, MongoDB does not require or generate _id on embedded objects. From the business solution standpoint, we can benefit from having a unique identifier at the Order Item level for tracking, and MongoDB ObjectID looks like an easy way to assign one. Also note the index: true property on this field - again, MongoDB would not auto-index _id on an embedded field. Arguably, we might have used a different field name all together, but _id looks consistent with how objects are marked in MongoDB.

Note the index: true for the item_id field and the type: Object designation for the item_details. We'll see later how the built-in object handling capabilities of JS allow us "merging" item_details from the Item Document with those specified at the Order Item level, overriding matching properties with the more specific values entered on the Order.


Well, that's all on MongoDB for now, let's move on to see how the GraphQL side of the solution works!

Edit Me on GitHub!