# MongoDB One-to-One relationship tutorial with Mongoose example

### Model One-to-One Relationships

Assume that we have 2 entity: _Identifier_ and _Customer_. For example:

```
// Identifier
{
   _id: "12345xyz",
   cardCode: "BKD2019",
}

// Customer
{
   _id: "cus123",
   name: "bezkoder",
   age: 29,
   gender: "male"
}
```

We want to map _Identifier_ and _Customer_ relationship in that:\
– One _Customer_ has only one _Identifier_.\
– One _Identifier_ belongs to only one _Customer_.

This is called One-to-One Relationship.\
Now let’s take a look at 2 ways to design schema for this kind of model.

#### Reference Data Models (Normalization)

In this model, an object A connects to the object B by reference to object B id or a unique identification field.

For example, _Identifier_ has a `customer_id` field which value is equal to _Customer_ object’s unique `_id` value.

```
// Identifier
{
   _id: "12345xyz",
   cardCode: "BKD2019",
   customer_id: "cus123",
}

// Customer
{
   _id: "cus123",  // equal Identifier[customer_id]
   name: "bezkoder",
   age: 29,
   gender: "male"
}
```

#### Embedded Data Models (Denormalization)

It’s easy to understand with ‘Embedded’ word. Instead of using a reference, Object A contains the whole object B, or object B is embedded inside object A.

You can see the example below, _Identifier_ will have a nested field `customer`.

```
// Identifier
{
   _id: "12345xyz",
   cardCode: "BKD2019",
   customer: {
                _id: "cus123", // Identifier[customer_id]
                name: "bezkoder",
                age: 29,
                gender: "male"
             }
}
```

You’ve known 2 ways to make One-to-One Relationships. Let’s implement each of them in a Node.js app using Mongoose. After that, I will tell you which model should be used for implementing One-to-One relationship between collections in MongoDb Database.

### Mongoose One-to-One relationship example

#### Setup Nodejs App

First we need to install **mongoose**, so run the command:

```
npm install mongoose
```

Next, we create project structure like this:

&#x20;src

&#x20;models

&#x20;Customer.js

&#x20;Identifier.js

&#x20;server.js

&#x20;package.json

Open _server.js_, we import `mongoose` to our app and connect to MongoDB database.

```
const mongoose = require("mongoose");

mongoose
  .connect("mongodb://localhost/bezkoder_db", {
    useNewUrlParser: true,
    useUnifiedTopology: true
  })
  .then(() => console.log("Successfully connect to MongoDB."))
  .catch(err => console.error("Connection error", err));
```

The first step is done, we’re gonna create appropriate models and use `mongoose` to interact with MongoDB database in two ways:

* Referencing
* Embedding

#### Mongoose One-to-One relationship: Referencing

**1. Define One-to-One models using Mongoose**

Let’s create 2 main model with `mongoose.Schema()` construtor function.

In _models/Customer.js_, define `Customer` with 3 fields: `name`, `age`, `gender`.

```
const mongoose = require("mongoose");

const Customer = mongoose.model(
  "Customer",
  new mongoose.Schema({
    name: String,
    age: Number,
    gender: String
  })
);

module.exports = Customer;
```

Identifier object will have `cardCode` field and a reference `customer`.\
So open _models/Identifier.js_, define `Identifier` like this:

```
const mongoose = require("mongoose");

const Identifier = mongoose.model(
  "Identifier",
  new mongoose.Schema({
    cardCode: String,
    customer: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Customer"
    }
  })
);

module.exports = Identifier;
```

In the code above, we add `customer` field, set its `type` to `ObjectId` and `ref` to `Customer`. What does it help?

Now if we save an Identifier to MongoDB database, a document will be added like this:

```
{
   _id : ObjectId("5da000be062dc522eccaedeb"),
   cardCode : "5DA000BC06",
   customer : ObjectId("5da000bc062dc522eccaedea"),
   __v : 0
}
```

Let’s test it, and I will show you how to get an Identifier object with full-fields Customer in this approach.

**2. Test with MongoDB database**

Open _server.js_, add the code below:

```
const Customer = require("./models/Customer");
const Identifier = require("./models/Identifier");

const createCustomer = function(name, age, gender) {
  const customer = new Customer({
    name,
    age,
    gender
  });

  return customer.save();
};

const createIdentifier = function(cardCode, customer) {
  const identifier = new Identifier({
    cardCode,
    customer
  });

  return identifier.save();
};

createCustomer("bezkoder", 29, "male")
  .then(customer => {
    console.log("> Created new Customer\n", customer);
    
    const customerId = customer._id.toString();
    return createIdentifier(customerId.substring(0, 10).toUpperCase(), customerId);
  })
  .then(identifier => {
    console.log("> Created new Identifier\n", identifier);
  })
  .catch(err => console.log(err));
```

Console shows the result.

```
> Created new Customer
 { _id: 5da135bd61a1dd3e9c2a6e81,
  name: 'bezkoder',
  age: 29,
  gender: 'male',
  __v: 0 }

> Created new Identifier
 { _id: 5da135bf61a1dd3e9c2a6e82,    
  cardCode: '5DA135BD61',
  customer: 5da135bd61a1dd3e9c2a6e81,
  __v: 0 }
```

We can check collections in the database.

![mongoose-one-to-one-relationship-example-nodejs-mongodb-reference](https://bezkoder.com/wp-content/uploads/2019/10/mongoose-one-to-one-relationship-example-nodejs-mongodb-reference.png)

As I’ve said before, the Identifier has only `ObjectId` in `customer` field.

The question is: How to get full items of `customer`?\
Oh yeah, we can reference documents in other collections using [populate()](https://mongoosejs.com/docs/populate.html).

Let me show you how to do this.

```
const showAllIdentifier = async function() {
  const identifiers = await Identifier.find().populate("customer");

  console.log("> All Identifiers\n", identifiers);
};
```

The result looks like this.

```
> All Identifiers
 [ { _id: 5da135bf61a1dd3e9c2a6e82,
    cardCode: '5DA135BD61',
    customer:
     { _id: 5da135bd61a1dd3e9c2a6e81,
       name: 'bezkoder',
       age: 29,
       gender: 'male',
       __v: 0 },
    __v: 0 } ]
```

**Mongoose Hide \_id & \_\_v in result**

If you don’t want to get `customer._id` & `customer.__v` in the result, just add second parameters to `populate()` function like this:

```
const identifiers = await Identifier.find()
    .populate("customer", "-_id -__v");
```

Check the result:

```
> All Identifiers
 [ { _id: 5da135bf61a1dd3e9c2a6e82,
    cardCode: '5DA135BD61',
    customer: { name: 'bezkoder', age: 29, gender: 'male' },
    __v: 0 } ]
```

How about `__v` in parent object?\
We use [`select()`](https://mongoosejs.com/docs/api.html#query_Query-select) function to remove it.

```
const identifiers = await Identifier.find()
    .populate("customer", "-_id -__v");
    .select("-__v");
```

The result will be:

```
> All Identifiers
 [ { _id: 5da135bf61a1dd3e9c2a6e82,
    cardCode: '5DA135BD61',
    customer: { name: 'bezkoder', age: 29, gender: 'male' } } ]
```

#### Mongoose One-to-One relationship: Embedding

**1. Define One-to-One models using Mongoose**

The way we define models for Embedded Documents will be different from Referenced Documents.

In _models/Customer.js_, we also define `Customer` like code above, but also export `CustomerSchema`.

```
const mongoose = require("mongoose");

const CustomerSchema = new mongoose.Schema({
  name: String,
  age: Number,
  gender: String
});

const Customer = mongoose.model("Customer", CustomerSchema);

module.exports = { Customer, CustomerSchema };
```

Identifier object will still have `cardCode` field & `customer` field. But instead using a reference, we assign import and `CustomerSchema` directly.

_models/Identifier.js_

```
const mongoose = require("mongoose");
const CustomerSchema = require("./Customer").CustomerSchema;

const Identifier = mongoose.model(
  "Identifier",
  new mongoose.Schema({
    cardCode: String,
    customer: CustomerSchema
  })
);

module.exports = Identifier;
```

**2. Test with MongoDB database**

Open _server.js_, the definition of `createCustomer` & `createIdentifier` functions will be the same as Referencing.

It’s a little change in how we call `createIdentifier()`. Instead passing `customerId`, we use `customer` object.

```
const Customer = require("./models/Customer").Customer;
const Identifier = require("./models/Identifier");

const createCustomer = function(name, age, gender) {
  const customer = new Customer({
    name,
    age,
    gender
  });

  return customer.save();
};

const createIdentifier = function(cardCode, customer) {
  const identifier = new Identifier({
    cardCode,
    customer
  });

  return identifier.save();
};

createCustomer("bezkoder", 29, "male")
  .then(customer => {
    console.log("> Created new Customer\n", customer);

    return createIdentifier(
      customer._id.toString().substring(0, 10).toUpperCase(),
      customer
    );
  })
  .then(identifier => {
    console.log("> Created new Identifier\n", identifier);
  })
  .catch(err => console.log(err));
```

Run the code, then check result in the console.

```
> Created new Customer
 { _id: 5da1406de666c118c89bba28,
  name: 'bezkoder',
  age: 29,
  gender: 'male',
  __v: 0 }

> Created new Identifier
 { _id: 5da1406fe666c118c89bba29,  
  cardCode: '5DA1406DE6',
  customer:
   { _id: 5da1406de666c118c89bba28,
     name: 'bezkoder',
     age: 29,
     gender: 'male',
     __v: 0 },
  __v: 0 }
```

Now look at our MongoDB database. Full _Customer_ object is embedded in _Identifier_ object now.

![mongoose-one-to-one-relationship-example-nodejs-mongodb-embedded](https://bezkoder.com/wp-content/uploads/2019/10/mongoose-one-to-one-relationship-example-nodejs-mongodb-embedded.png)

To get the items in `identifiers` collections, just use `find()` function.

```
const showAllIdentifier = async function() {
  const identifiers = await Identifier.find();

  console.log("> All Identifiers\n", identifiers);
};
```

And you can see all things you want in the result:

```
> All Identifiers
 [ { _id: 5da1406fe666c118c89bba29,  
    cardCode: '5DA1406DE6',
    customer:
     { _id: 5da1406de666c118c89bba28,
       name: 'bezkoder',
       age: 29,
       gender: 'male',
       __v: 0 },
    __v: 0 } ]
```

**Mongoose Hide \_id & \_\_v in result**

With embedded documents, to hide `_id` & `__v` is easy with only one `select()` function.

For example, if I want to remove Identifier `__v`, also embedded document (Customer) fields such as `customer._id` & `customer.__v`, just write `select()` with parameter like this.

```
const showAllIdentifier = async function() {
  const identifiers = await Identifier.find()
    .select("-__v -customer.__v -customer._id");

  console.log("> All Identifiers\n", identifiers);
};
```

Now the result is pretty.

```
> All Identifiers
 [ { _id: 5da1406fe666c118c89bba29,
    cardCode: '5DA1406DE6',
    customer: { name: 'bezkoder', age: 29, gender: 'male' } } ]
```

### Referencing or Embedding for One-to-One Relationships

To make One-to-One Relationship between documents, we can reference or embed a document in the other. Which should be used in general?

Now remind what we’ve done and you can see that we have to use an additional function called `populate()` after `find()` function for Referenced Data Model.

Embedding stores related information directly inside the objects. So we only use `find()` function to get everything. It gives us better performance with a single query. This Model also helps us update the embedded data in just one query using [Dot Notation](https://docs.mongodb.com/manual/core/document/#document-dot-notation).

So the answer is that modeling One-to-One relationships with Embedded documents is the better choice.
