Introduction: Different Data Structures for Different Needs

In the previous lessons, you've become proficient with Google Cloud Firestore in Native Mode. You learned how to create collections and documents, perform CRUD operations, and efficiently query your data. You've seen how Native Mode organizes data as flexible documents that can contain nested objects and arrays. When you needed to represent relationships between data, like a blog post and its comments, you could embed the comments directly in the post document. This approach works well for many applications, particularly when you have hierarchical data and need to retrieve related information together.

However, as you work with more complex applications, you'll encounter scenarios where a different model better fits your needs. Consider an application that primarily performs key-based lookups, like a session management system where you always retrieve sessions by session ID. Or think about scenarios requiring transactions across multiple root-level entities, like updating separate account and transaction entities atomically. Native Mode's flexible documents work best when related data is nested together, but this approach has limitations when you need to manage relationships across multiple independent documents.

This is where Firestore in Datastore Mode comes in, and this lesson focuses specifically on Firestore in Datastore mode's approach to data modeling. Datastore mode is GCP's entity-based NoSQL database that's backward compatible with Cloud Datastore. Unlike Native mode's flexible documents with deep nesting, Datastore mode uses an entity model where data is stored as entities with flat properties and hierarchical keys. This structured approach provides strong consistency within entity groups and enables transactions across up to 25 entity groups, which is useful for applications with complex multi-entity operations.

In this lesson, you'll learn how to model data using Firestore in Datastore mode's entity model, focusing on entities, ancestor keys, and entity groups. You'll see the same data represented in both modes and understand when entities with ancestor relationships provide advantages over nested documents. By the end of this lesson, you'll be able to recognize which Firestore mode fits your application's needs better. You'll understand that choosing between them isn't about one being better than the other, but rather about matching the database model to your data's structure and access patterns.

Understanding the Entity Model

An entity in Datastore mode is a structured data object consisting of a unique key and a set of properties. Unlike Native mode documents that can have deeply nested objects and arrays, an entity's properties are relatively flat. Think of an entity as a structured piece of information designed for efficient key-based access with strong consistency guarantees.

In Datastore mode, entities are organized into kinds, similar to Native mode collections. However, entities are designed around indexed properties and ancestor relationships rather than flexible nesting. This means you work with entities as discrete units that can be linked through hierarchical keys rather than embedding related data as nested objects.

The power of the entity model comes from ancestor keys and entity groups. Instead of storing related information as nested fields within a single document, you create entities with hierarchical keys that establish parent-child relationships. For example, a blog post entity can have comment entities as descendants, where each comment's key includes the post's key as an ancestor. All entities sharing a common ancestor form an entity group, which provides strong consistency guarantees and supports transactions with full ACID properties.

This approach provides predictable consistency and performance. In Native mode, embedding comments inside a blog post limits you to 1 MiB per document and requires reading/writing the entire document for any update. With Datastore mode, each comment is a separate entity, so you can update individual comments independently without size constraints. The entity group model ensures that when you query for a post and its comments, you see a consistent snapshot of the data, which is important for transactional applications.

Same Data, Two Approaches: A Blog Post Example

To understand the practical difference between these modes, let's look at how you would represent the same blog post in both Native mode and Datastore mode. Imagine you're building a blogging platform where each post has an author, content, tags, comments, and view counts.

In Native mode, you structure this as a single document with nested objects and arrays. The blog post document contains a nested author object, a comments array of comment objects, and a metadata object. All information lives together in one document. Here's how this looks:

Notice how everything is contained in a single document with nested structures. To display this blog post, you make one query that retrieves the entire document.

Now let's see the same data in Datastore mode using the entity model. One difference you'll notice immediately is that Datastore mode requires you to explicitly specify your GCP project ID when creating the client. Both Firestore modes operate within GCP projects, but Datastore mode's client initialization requires the project parameter. In production, you would use your actual project ID, but for examples we'll use :

Querying Entities: Datastore Mode's Indexed Approach

A key difference between modes is how queries work. Native mode lets you query nested fields using dot notation. Datastore mode queries work on flat entity properties and require those properties to be indexed. While single-property queries use automatic indexes, complex queries require composite indexes defined explicitly.

Here's how query patterns work in Datastore mode:

The first query searches by a property value using an automatic index. Unlike Native mode where you could query author.email, Datastore mode works with flat properties, so author email must be at the top level.

The second query combines multiple conditions but requires a composite index defined in index.yaml. Native mode allows querying multiple fields without pre-configured indexes in most cases.

The third query demonstrates array filtering. When you store tags as an array, Datastore mode indexes each value automatically.

The fourth query shows ancestor queries, unique to Datastore mode. By specifying ancestor=post_key, you retrieve all comments belonging to that post with strong consistency. Native mode doesn't have entity groups or ancestor queries.

Updating Entities: Property-Level Operations

Updating entities in Datastore mode differs from Native mode's atomic operators. Native mode provides operators like firestore.Increment() and firestore.ArrayUnion() for atomic updates. Datastore mode typically uses read-modify-write patterns or transactions.

Here's how update operations work in Datastore mode:

The first operation increments a counter using read-modify-write, different from Native mode's atomic Increment(). Without a transaction, there's risk of race conditions.

The second operation adds a comment by creating a new entity rather than using ArrayUnion(). This entity can be managed independently without affecting the post entity's size.

The third operation manages arrays by explicitly checking for duplicates and modifying in memory, more manual than Native mode's ArrayUnion().

The fourth operation uses transactions for consistency, supporting up to 25 entity groups with full ACID properties.

Choosing Your Firestore Mode: Entity vs Document Model

Now that you understand both modes, you need to know when to choose each one. The decision depends on your data structure, access patterns, and consistency requirements.

You should use Native mode when your data is naturally hierarchical with nested structures like product catalogs with embedded specifications, user profiles with preferences, or content management systems. Native mode is better when you need flexible query patterns that might change over time or when you want to minimize database operations to retrieve related information. The document model shines when you want atomic update operators for nested fields and arrays without complex read-modify-write patterns.

You should use Datastore mode when your data access patterns are well-defined and centered around key-based lookups. If you're building session management systems or inventory systems with predictable lookups, Datastore mode excels. It's particularly useful when you need transactions across multiple root-level entities within an entity group or need to maintain backward compatibility with Cloud Datastore for migration scenarios.

The trade-offs involve several dimensions. Native mode offers flexibility with deep nesting but has document size limits. Datastore mode offers predictable performance for key-based access and supports transactions across multiple entity groups but requires composite indexes for complex queries and explicit relationship management through ancestor keys.

Here's a comparison of how the approaches differ:

This shows the practical differences. Native mode retrieves posts with comments in one query, uses simple atomic operations, and queries nested fields directly. Datastore mode requires multiple queries but provides independent entity management, transactional updates across entity groups, and explicit relationship control through ancestor keys.

Summary: Understanding Your Firestore Options

You now understand two different ways to use Google Cloud Firestore. Native mode's document model excels at representing hierarchical data with nested objects and arrays, offering flexible queries without requiring pre-configured indexes for most use cases. Datastore mode's entity model provides predictable performance for key-based lookups with strong consistency guarantees within entity groups, making it ideal for transactional applications with well-defined access patterns. Neither mode is universally better than the other; the right choice depends on your data structure, access patterns, and consistency requirements.

In the upcoming practice exercises, you'll work with code that demonstrates both modes side by side. You'll see how to transform Native mode's nested document structure into Datastore mode's entity structure with ancestor relationships. You'll practice creating entities with indexed properties, querying with filters and ancestor queries, and updating entities within transactions. These exercises will help you develop intuition for recognizing when the entity model provides advantages over the document model, a skill that will guide your Firestore mode choices in real-world applications.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal