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!