Get Object Id as primary key to a return method in Java

I try to get the _id field from the existing collection in MongoDB to my return method so I can use that oid to edit user document, but the include keyword prompts me to create a new method. Am using 3.12 and follow the projections for guidance. Any advice will be highly appreciated!

findIterable = collection.find(eq("status", "A")).projection(include("item", "status"));

    @Override
    public User get(Object userId) {
        
    MongoCollection<Document> userTbl = database.getCollection("User");

    FindIterable<Document> findIterable = userTbl.find().projection(include("email")); // error

    userId = findIterable;
        
    return (User) userId;
    }

Hi @Pat_Yue and welcome in the MongoDB Community :muscle: !

I’m not sure I completely understood your question but here is a little piece of Java that explains how to retrieve an ObjectId as a String and then reusing it to update the documents in the collection.

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Projections;
import com.mongodb.client.model.Updates;
import org.bson.Document;
import org.bson.types.ObjectId;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.mongodb.client.model.Filters.eq;
import static com.mongodb.client.model.Projections.include;

public class Community {

    public static void main(String[] args) {
        try (MongoClient mongoClient = MongoClients.create("mongodb://localhost")) {
            MongoCollection<Document> coll = mongoClient.getDatabase("test").getCollection("coll");
            coll.drop();
            coll.insertMany(
                    Arrays.asList(new Document("name", "Max"), new Document("name", "Alex"), new Document("name", "Claire")));
            List<Document> docs = coll.find().projection(include("_id")).into(new ArrayList<>());
            System.out.println("Printing the ObjectIds from the 3 docs:");
            docs.forEach(doc -> System.out.println(doc.get("_id")));

            System.out.println("\nUpdating the 3 documents using their respective IDs:");
            docs.forEach(doc -> {
                String stringId = doc.get("_id").toString();
                ObjectId objectId = new ObjectId(stringId);
                coll.updateOne(eq("_id", objectId), Updates.set("hobby", "gaming"));
            });

            docs = coll.find().into(new ArrayList<>());
            docs.forEach(doc -> System.out.println(doc.toJson()));
        }
    }
}

I think the code is pretty self explanatory but please feel free to ask me questions is something isn’t clear.

This is the output I get:

Printing the ObjectIds from the 3 docs:
5f8757f9e42cd148f41b29c8
5f8757f9e42cd148f41b29c9
5f8757f9e42cd148f41b29ca

Updating the 3 documents using their respective IDs:
{"_id": {"$oid": "5f8757f9e42cd148f41b29c8"}, "name": "Max", "hobby": "gaming"}
{"_id": {"$oid": "5f8757f9e42cd148f41b29c9"}, "name": "Alex", "hobby": "gaming"}
{"_id": {"$oid": "5f8757f9e42cd148f41b29ca"}, "name": "Claire", "hobby": "gaming"}

I hope this helps.

Cheers,
Maxime.

1 Like

Thanks for your reply. I worked it out this way while learning Java and MongoDB together.

public User get(Object userId) {

	FindIterable<User> userTbl = database.getCollection("User", User.class).find();		

for (User doc : userTbl) {
	String id = doc.getId().toString();
	System.out.println("MongoDB _id = " + id);

		if (id.equals(userId)) {
			return doc;
		}
	}
	return null;
}

I wonder how does the lambda function to work in above instead output into the console?

Thanks so much in advance.

Your function isn’t optimised at all.

First it’s returning ALL the documents in the “User” collection to your Java (so potentially millions of documents) and then if ONE of the documents has the “_id” you are looking for, then you return this document.

The find() function takes a filter in parameter which you can leverage here to simplify your code and only fetch that ONE document you are looking for.

Here is how you should write this get function:

private static Document getUser(String id) {
    return coll.find(eq("_id", new ObjectId(id))).first();
}

Here it is in action:

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.result.InsertManyResult;
import org.bson.Document;
import org.bson.types.ObjectId;

import java.util.Arrays;

import static com.mongodb.client.model.Filters.eq;

public class Community {

    private static MongoCollection<Document> coll;

    public static void main(String[] args) {
        try (MongoClient mongoClient = MongoClients.create("mongodb://localhost")) {
            coll = mongoClient.getDatabase("test").getCollection("coll");
            coll.drop();
            InsertManyResult insertManyResult = coll.insertMany(
                    Arrays.asList(new Document("name", "Max"), new Document("name", "Alex"), new Document("name", "Claire")));
            insertManyResult.getInsertedIds()
                            .forEach((ignoredInt, id) -> System.out.println(getUser(id.asObjectId().getValue().toHexString())));
        }
    }

    private static Document getUser(String id) {
        return coll.find(eq("_id", new ObjectId(id))).first();
    }
}

Also note that this function can benefit from the default _id index that exists in all the MongoDB collections by default, so it’s not doing a collection scan to find this one document in your collection.

If you did a search on the name, you would have to create an index on that field to avoid a collection scan.

More details here: https://docs.mongodb.com/manual/tutorial/analyze-query-plan/

2 Likes

I can’t see any below option in eclipse, is that need to be imported manually? Thanks.

InsertManyResult comes from this package.
I use IntelliJ and it resolves my imports automatically when there are no doubts between 2 classes.

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.