How to design the user/order/shipping model in mongo for a e-commerce app?

Viewed 184

Every order has a shipping info and every user has several shipping addresses. This is my design:

User:
   ...
   defaultAddress: ObjectId
   ...
Address:
   ...
   ...   
   ...
Order:
   ...
   shipping: ObjectId  
   ...

Here are my questions:

  1. Is it reasonable to use a reference for shipping in Order Model, or just embed the entire Address object.
  2. Every time add a new address from App, Is there any better way to check if it is already exist in mongodb?
  3. Should I keep a defaultAddress key in User Model, or should I just use a array to keep all the address object?

Thanks very much.

1 Answers

Addresses bind closely to Users, so make Addresses an array inside Users.

Depending on your overall audit / revisioning data architecture, you may wish to copy the address into the Order doc upon creation to create an unambiguous record of where it went. Having Order reference back into User and address implies you cannot change the address; you would have to mark it as no longer active but not deleted. Note you do not have to laborious copy all the fields; you can treat the selected address as an object, something like:

var addr = get addr;  // from DB or wherever; any shape with any number of subfields is fine.                                 

db.order.insert({orderId:"someID", date:new ISODate(), shippingAddress: addr});

To prevent dupes, it is a matter of looking up the info in the array -- but of course caveats apply such as making sure you canonicalize case, strip white space, remove unnecessary punctuation, etc. etc. Let's assume you have street,city, and state as the matchable fields:

{
    "user":"U1",
    "addrs": [
        {street: "20 Pine Ln", city: "Smallville", state: 'NM'},
        {street: "16 Elm Ln", city: "Denver", state: 'CO'},
        {street: "77 Sunshine Pkway", city: "Denver", state: 'CO'},
    ]
}

After grooming the input from app, assume we have a target lookup doc like this. Note: We do NOT have to create the doc with fields in a particular order.

var target = {city: "Denver", state: 'CO', street: '16 Elm Ln'};

The lookup is simple. Since addrs is an array, the match will dive into and iterate over the array. The $elemMatch operator ensures that ALL fields in the candidate match those in the target.

db.foo.aggregate([
    {$match: {user:'U1', "addrs":{$elemMatch: target} }}
]);

If no records are found, then this is a new address.

Related