The following examples illustrate a number of ways the normalization of complex types are handled.

A subdocument nested in a subdocument

In this example, the subdocument location contains the subdocuments city and state in the employee collection:

{"_id": "pdn313",
 "name": "Charlotte",
 "manager": {"name": "Robert", "department": "Development",
           "location": {"city": "Tulsa", "state": "OK"}}
}

{"_id": "gkx136",
 "name": "Benjamin",
 "manager": {"name": "Michael", "department": "Quality Assurance",
           "location": {"city": "Dallas", "state": "TX"}}
}

The information in the employee collection would be mapped to the EMPLOYEE parent table, and the EMPLOYEE_MANAGER and the EMPLOYEE_LOCATION child tables. The EMPLOYEE table would be derived from the simple types _id and name as follows:

Table 1. EMPLOYEE
_ID NAME
pdn313 Charlotte
gkx136 Benjamin

The information from the manager object is mapped to the following child table:

Table 2. EMPLOYEE_MANAGER
NAME DEPARTMENT
pdn313 Robert Development
gkx136 Michael Quality Assurance
The mapping of the manager object to the EMPLOYEE_MANAGER table is handled as follows:
  • The table name, EMPLOYEE_MANAGER, is derived from the name of the parent table and the object.
  • To establish a foreign key relationship with the parent table, a column is generated based on the _ID field using the following naming convention:
    <parent_table>_ID 

    For example, EMPLOYEE_ID.

  • The nested subdocuments are mapped to columns in the child table. For example, the name field is mapped to the NAME column.

The information in the location object is mapped to the following child table:

Table 3. EMPLOYEE_LOCATION
EMPLOYEE_ID (PK & FK) CITY STATE
pdn313 Tulsa OK
gkx136 Dallas TX
The mapping of the location object to the EMPLOYEE_LOCATION table is handled as follows:
  • The table name, EMPLOYEE_LOCATION, is derived from the name of the parent table and the object.
  • The id_ field is mapped as EMPLOYEE_ID to establish a foreign key relationship to the parent table.
  • Nested subdocuments are mapped to columns. In this example, the city and state subdocuments, which indicate the location of an employee's manager, are mapped as CITY and STATE columns.

Subdocuments nested in an array

In the collection contacts, the addresses array contains the subdocuments: label, street, city, and state.

{"_id": "ajx456",
 "name": "Andrea",
 "addresses": [
             {"label": "Home", "street": "101 Main St", "zip": "27513"},
             {"label": "Work", "street": "303 Main St", "zip": "27560"} 
             ]
}

The information in the contacts collection would be mapped to the CONTACT parent table, and the CONTACTS_ADDRESSES child table. The CONTACTS table would be derived from the simple types _id and name as follows:

Table 4. CONTACTS
_ID NAME
ajx456 Andrea

The information in the addresses array maps to the following child table:

Table 5. CONTACTS_ADDRESSES
CONTACTS_ID (FK) POSITION (PK) LABEL STREET ZIP
ajx456 0 Home 101 Main St 27513
ajx456 1 Work 303 Main St 27560
The mapping of the addresses array to the CONTACTS_ADDRESSES tables is handled as follows:
  • The table name, CONTACTS_ADDRESSES, is derived from the name of the parent table and array.
  • To establish a foreign key relationship with the parent table, a column is generated based on the _ID field using the following naming convention:
    <parent_table>_ID 

    For example, CONTACTS_ID.

  • The primary key of the child table is a composite key formed by the primary key of the parent table (CONTACTS_ID) combined with the positional information contained in the POSITION column.
  • Subdocuments in an array are mapped as columns. For example, the label field is mapped to the LABEL column.

An array nested in a document

In a separate scenario, the manager document contains the emails array in the employee collection. The collection has the following JSON structure:

{"_id": "ajp211",
 "name": "Mark",
 "manager": {"name": "Cynthia",
           "emails": ["cynthia@email.com", "watsonc@email.com"]}
}
{"_id": "mpc393",
 "name": "Deborah",
 "manager": {"name": "Cynthia",
           "emails": ["cynthia@email.com", "watsonc@email.com"]}
}
{"_id": "dlm215",
 "name": "Jason",
 "manager": {"name": "Chris",
           "emails": ["chris@email.com", "cwright@email.com"]}
}

The information in the employee collection would be mapped to the EMPLOYEE parent table, and the EMPLOYEE_EMAILS and EMPLOYEE_MANAGER child tables. The EMPLOYEE table would be derived from the simple types _id and name as follows:

Table 6. EMPLOYEE
_ID NAME
ajp211 Mark
mpc393 Deborah
dlm215 Jason

The information in the emails array is mapped to the following child table:

Table 7. EMPLOYEE_EMAILS
EMPLOYEE_ID (FK) POSITION EMAILS
ajp211 0 cynthia@email.com
ajp211 1 watsonc@email.com
mpc393 0 cynthia@email.com
mpc393 1 watsonc@email.com
dlm215 0 chris@email.com
dlm215 1 cwright@email.com
The mapping of the nested emails array to the EMPLOYEE_EMAILS table is handled as follows:
  • The table name, EMPLOYEE_EMAILS, is derived from the name of the parent table and the array.
  • To establish a foreign key relationship with the parent table, a column is generated based on the _ID field using the following naming convention:
    <parent_table>_ID 

    For example, EMPLOYEE_ID.

  • The primary key of the child table is a composite key formed by the primary key of the parent table (EMPLOYEE_ID) combined with the positional information contained in the POSITION column.
  • Nested arrays are mapped as columns. For example, the emails array is mapped to the EMAILS column. Note that the emails in the following child table are those of the managers, but correspond to the employee identification number.
The information in the names subdocument is mapped to the following child table:
Table 8. EMPLOYEE_MANAGER
EMPLOYEE_ID (PK & FK) NAME
ajp211 Cynthia
mpc393 Cynthia
dlm215 Chris
The mapping of the nested names subdocument to the EMPLOYEE_MANAGER table is handled as follows:
  • The table name, EMPLOYEE_MANAGER, is derived from the name of the parent table and the object.
  • To establish a foreign key relationship with the parent table, a column is generated based on the _ID field using the following naming convention:
    <parent_table>_ID 

    For example, EMPLOYEE_ID.

  • The nested name subdocument (the name of the manager) is mapped as a column. Note that the names in the following child table are those of the managers, but correspond to the employee identification number.

An array nested in an array

In the collection offices, the departments array contains an employees array.

{"_id": "au32",
 "city": "Bedford",
 "departments": [{"name": "Development",
                  "employees": [
                                {"first": "Leslie", "last": "Jacobs"},
                                {"first": "Emma", "last": "Alves"},
                                {"first": "Brad", "last": "Jones"}
                               ]
                 },
                 {"name": "Human Resources",
                  "employees": [
                                {"first": "Joseph", "last": "Lu"},
                                {"first": "Margaret", "last": "Baker"},
                                {"first": "Chetna", "last": "Campbell"}
                               ]
                 },
                 {"name": "IT",
                  "employees": [
                                {"first": "Caroline", "last": "Evans"},
                                {"first": "Markus", "last": "Campanella"},
                                {"first": "Jennifer", "last": "Bradley"}
                               ]
                 }]
 }
{"_id": "xn44",
 "city": "Morrisville",
 "departments": [{"name": "Development",
                  "employees": [
                                {"first": "Charles", "last": "Scott"},
                                {"first": "Mary", "last": "Gonzales"},
                                {"first": "Phil", "last": "McEnroe"}
                               ]
                 },
                 {"name": "Operations",
                  "employees": [
                                {"first": "Rachel", "last": "Cullingford"},
                                {"first": "Lance", "last": "Friedman"},
                                {"first": "Amanda", "last": "Giachetti"}
                               ]
                 },
                 {"name": "IT",
                  "employees": [
                                {"first": "Ingrid", "last": "Burkis"},
                                {"first": "Catherine", "last": "Wheeler"},
                                {"first": "Jacob", "last": "Williams"}
                               ]
                 }]
}

The information in the offices collection would be mapped to the OFFICES parent table, and the OFFICES_DEPARTMENTS and OFFICES_EMPLOYEES child tables. The OFFICES table would be derived from the simple types _id and city as follows:

Table 9. OFFICES
_ID (PK) CITY
au32 Bedford
xn44 Morrisville

The information in the departments nested array is mapped to the following child table:

Table 10. OFFICES_DEPARTMENTS
OFFICES_ID (FK) POSITION (PK) NAME
au32 0 Development
au32 1 Human Resources
au32 2 IT
xn44 0 Development
xn44 1 Operations
xn44 2 IT
The mapping of the departments nested array to the OFFICES_DEPARTMENTS table is handled as follows:
  • The table name, OFFICES_DEPARTMENTS, is derived from the name of the parent table and the array.
  • To establish a foreign key relationship with the parent table, a column is generated based on the _ID field using the following naming convention:
    <parent_table>_ID 

    For example, OFFICES_ID.

  • The primary key of the child table is a composite key formed by the primary key of the parent table (OFFICES_ID) combined with the positional information contained in the POSITION column.
  • Nested arrays are mapped as columns. For example, the name array is mapped to the NAME column.

The information in the employees array is mapped to the following child table:

Table 11. OFFICES_EMPLOYEES

OFFICES_ID (FK)

OFFICES_ DEPARTMENTS _POSITION POSITION (PK) FIRST LAST
au32 0 0 Leslie Jacobs
au32 0 1 Emma Alves
au32 0 2 Brad Jones
au32 1 0 Joseph Lu
au32 1 1 Margaret Baker
au32 1 2 Chetna Campbell
au32 2 0 Caroline Evans
au32 2 1 Markus Campanella
au32 2 2 Jennifer Bradley
xn44 0 0 Charles Scott
xn44 0 1 Mary Gonzales
xn44 0 2 Phil McEnroe
xn44 1 0 Rachel Cullingford
xn44 1 1 Lance Friedman
xn44 1 2 Amanda Giachetti
xn44 2 0 Ingrid Burkis
xn44 2 1 Catherine Wheeler
xn44 2 2 Jacob Williams
The mapping of the nested employees array to the OFFICES_EMPLOYEES table is handled as follows:
  • The table name, OFFICES_EMPLOYEES, is derived from the name of the parent table and the array.
  • The OFFICES_ID and OFFICES_DEPARTMENTS_POSITION columns establish a foreign key relationship to the parent array based on the primary key from the DEPARTMENTS table.
  • The primary key of the child table is a composite key formed by the primary key of the parent table (OFFICES_ID) combined with the positional information contained in the POSITION column.
  • Nested arrays are mapped as columns. For example, the first array is mapped to the FIRST column.