Skip to main content

Nested Documents

CouchbaseOrm supports nested documents, which allow you to store complex, hierarchical data structures within a single Couchbase document. Nested documents are useful when you have related data that you want to store together with the parent document for performance or consistency reasons.

9.1. Defining Nested Documents

To define an nested document, you create a new class that inherits from CouchbaseOrm::NestedDocument.

class Part < CouchbaseOrm::NestedDocument
attribute :name, :string
attribute :manufacturer, :string
end

# Define the Car model with a nested Part document
class Car < CouchbaseOrm::Base
attribute :make, :string
attribute :model, :string
attribute :year, :integer
attribute :parts, :array, type: Part

validates :make, presence: true
validates :model, presence: true
validates :year, presence: true
end

In this example, we define a Car model with a nested Part document. The Part class inherits from CouchbaseOrm::NestedDocument and defines attributes for name and manufacturer. The Car model has an parts attribute that is an array of Part nested documents.

9.2. Embedding Documents

To embed a document within a parent document, you can assign an instance of the nested document class to the corresponding attribute.

# Create a new car with nested parts
car = Car.new(
make: 'Toyota',
model: 'Corolla',
year: 2022,
parts: [
Part.new(name: 'Engine', manufacturer: 'Toyota Motors'),
Part.new(name: 'Transmission', manufacturer: 'Toyota Motors')
]
)
car.save

When saving the parent document (Car), CouchbaseOrm serializes the nested Part documents and stores them within the parent document. This allows you to retrieve the entire data structure with a single query.

9.3. Accessing Nested Documents

To access an nested document, you can simply call the corresponding attribute on the parent document.

toyota_cars = Car.where(make: 'Toyota')

CouchbaseOrm automatically deserializes the nested document and returns an instance of the nested document class.

9.4. Updating Nested Documents

To update an nested document, you can modify the attributes of the nested document instance and save the parent document.

engine_part = car.parts.find { |part| part.name == 'Engine' }
engine_part.manufacturer = 'Toyota Industries'
car.save

CouchbaseOrm will serialize the updated nested document and save it along with the parent document.

9.5. Embedding Multiple Documents

You can also embed multiple documents within a parent document using an array attribute.

car = Car.new(
make: 'Toyota',
model: 'Corolla',
year: 2022,
parts: [
Part.new(name: 'Engine', manufacturer: 'Toyota Motors'),
Part.new(name: 'Transmission', manufacturer: 'Toyota Motors')
]
)
car.save

In this example, the Car model has an parts attribute that is an array of Part nested documents. You can embed multiple Part documents within a single Car document, allowing you to store related data together.

9.6. Querying Nested Documents

CouchbaseOrm allows you to query nested documents using dot notation and attribute conditions.

cars_by_part_manufacturer = Car.where("ANY part IN parts SATISFIES part.manufacturer = 'Toyota Industries' END")

This query retrieves all the Car documents where at least one Part document has a manufacturer attribute equal to 'Toyota Industries'. You can use dot notation to access nested document attributes within the query condition.

9.7. Validating Nested Documents

CouchbaseOrm allows you to validate nested documents along with the parent document.

class Part < CouchbaseOrm::NestedDocument
attribute :name, :string
attribute :manufacturer, :string

validates :name, presence: true
validates :manufacturer, presence: true
end

class Car < CouchbaseOrm::Base
attribute :make, :string
attribute :model, :string
attribute :year, :integer
attribute :parts, :array, type: Part

validates :make, presence: true
validates :model, presence: true
validates :year, presence: true
validates :parts, presence: true
end


In this example, we define validations for the Part nested document, ensuring that the name and manufacturer attributes are present. We also add validations to the Car model to ensure that the make, model, year, and parts attributes are present.

When saving a Car document, CouchbaseOrm will validate both the parent document and the nested Part documents. If any validation fails, the parent document will not be saved, and validation errors will be added to the parent document.

Nested documents provide a powerful way to model complex data structures and relationships within a single Couchbase document. They allow you to store related data together, improving performance and reducing the need for separate queries to retrieve associated data.

However, it's important to consider the trade-offs when using nested documents. Embedding too much data within a single document can lead to large document sizes and potential performance issues. It's recommended to use nested documents judiciously and to consider the access patterns and data relationships of your application.

In the next section, we'll explore enums in CouchbaseOrm and how they can be used to define a fixed set of values for an attribute.