NoSQL databases provide flexible schema designs that make them ideal for handling complex and hierarchical data structures. One of the most powerful features of NoSQL is its ability to store embedded data within documents, reducing the need for costly joins and improving performance. In this article, we will explore how to handle embedded data in NoSQL using Java, focusing on MongoDB, a widely used document-based NoSQL database.

Understanding Embedded Data in NoSQL

Unlike traditional relational databases, where related data is stored in separate tables and linked through foreign keys, NoSQL databases often embed related objects within a single document. This approach enhances data retrieval efficiency by reducing the need for multiple queries.

For instance, consider a simple User object that contains multiple Address objects. Instead of storing addresses in a separate collection, we can embed them directly within the user document.

Setting Up MongoDB With Java

Before we start coding, ensure that MongoDB is installed on your system and that you have the required dependencies in your Java project. If using Maven, add the following dependency to your pom.xml file:

<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongodb-driver-sync</artifactId>
    <version>4.6.1</version>
</dependency>

Defining Java Classes for Embedded Documents

Let’s define a User class where addresses are embedded within the user document.

import org.bson.codecs.pojo.annotations.BsonProperty;
import org.bson.codecs.pojo.annotations.BsonIgnore;
import org.bson.types.ObjectId;
import java.util.List;

class Address {
    private String street;
    private String city;
    private String zipCode;
    
    public Address(String street, String city, String zipCode) {
        this.street = street;
        this.city = city;
        this.zipCode = zipCode;
    }
    
    // Getters and Setters omitted for brevity
}

class User {
    private ObjectId id;
    private String name;
    private List<Address> addresses;

    public User(String name, List<Address> addresses) {
        this.id = new ObjectId();
        this.name = name;
        this.addresses = addresses;
    }
    
    // Getters and Setters omitted for brevity
}

Connecting to MongoDB

To interact with MongoDB, we need to create a connection using the MongoDB Java Driver.

import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoCollection;

public class MongoDBConnection {
    public static MongoDatabase getDatabase() {
        MongoClient client = MongoClients.create("mongodb://localhost:27017");
        return client.getDatabase("mydatabase");
    }
}

Inserting Embedded Documents

Let’s insert a User document with embedded Address objects into MongoDB.

import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import java.util.Arrays;

public class InsertUserData {
    public static void main(String[] args) {
        MongoDatabase database = MongoDBConnection.getDatabase();
        MongoCollection<Document> collection = database.getCollection("users");

        Document address1 = new Document("street", "123 Main St")
                .append("city", "New York")
                .append("zipCode", "10001");
        Document address2 = new Document("street", "456 Elm St")
                .append("city", "Los Angeles")
                .append("zipCode", "90001");

        Document user = new Document("name", "John Doe")
                .append("addresses", Arrays.asList(address1, address2));

        collection.insertOne(user);
        System.out.println("User inserted successfully");
    }
}

Querying Embedded Data

To retrieve users and their embedded addresses, use the following query:

import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;

public class QueryUserData {
    public static void main(String[] args) {
        MongoDatabase database = MongoDBConnection.getDatabase();
        MongoCollection<Document> collection = database.getCollection("users");
        
        FindIterable<Document> users = collection.find();
        for (Document user : users) {
            System.out.println(user.toJson());
        }
    }
}

Updating Embedded Data

To update an embedded address for a specific user:

import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import org.bson.Document;

public class UpdateUserData {
    public static void main(String[] args) {
        MongoDatabase database = MongoDBConnection.getDatabase();
        MongoCollection<Document> collection = database.getCollection("users");

        collection.updateOne(
            Filters.eq("name", "John Doe"),
            Updates.set("addresses.0.city", "San Francisco")
        );
        
        System.out.println("User address updated successfully");
    }
}

Deleting Embedded Data

To remove an address from the embedded array:

import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import org.bson.Document;
import java.util.Collections;

public class DeleteUserData {
    public static void main(String[] args) {
        MongoDatabase database = MongoDBConnection.getDatabase();
        MongoCollection<Document> collection = database.getCollection("users");
        
        collection.updateOne(
            Filters.eq("name", "John Doe"),
            Updates.pull("addresses", new Document("city", "San Francisco"))
        );
        
        System.out.println("User address deleted successfully");
    }
}

Conclusion

Handling embedded data in NoSQL with Java provides an efficient way to store and manage hierarchical relationships. Unlike relational databases, NoSQL allows embedding related entities directly within documents, reducing the complexity of joins and improving read performance.

In this article, we covered:

  • How to model embedded data in Java for MongoDB.
  • How to insert, query, update, and delete embedded data efficiently.
  • The advantages of using embedded documents in NoSQL databases.

By leveraging MongoDB’s flexible schema and the MongoDB Java driver, developers can build scalable and efficient applications that handle complex data relationships seamlessly.