0

I'm having issues with a really simple task, in Java: I need to get "users" array inside an object,

Check if it contains a key ID, and if not, add a new user to the array. I don't get any error, but the user isn't added.

Please, answer using the Java driver. Why is that? Here is the code:

List<DBObject> queryResultList = cursor.toArray(1);
DBObject currentObj = queryResultList.get(0);
Set userIdsKeySet = ((BasicDBObject) currentObj.get("users")).keySet();
BasicDBObject newObj = null;
if(!userIdsKeySet.contains(userId)){
    ((BasicDBList)currentObj.get("users")).add(new BasicDBObject().append(userId, user));
}
if(newObj != null) {
    collection.update(currentObj, new BasicDBObject("users", newObj));
    return true;
}

The document structure looks like that:

{
    "_id": "5de9604ef36d7f394a4ade2f",
    "_index": "sw0dfb0",
    "users": [{
        "e9604ef36d94a4ade7f394": {
            "some_field": "abcde"
        }
    }]
}

Is it a better way to make the users array this way?

"users": [{
     "user_id":"e9604ef36d94a4ade7f394",
     "some_field":"abcde"
}]

Note: I Know there are much prettier and simpler ways to do it, any informative advice is welcome.

5
  • 1
    by the way, its considered bad form to use data points (for example e9604ef36d94a4ade7f394) as a key in a key-value store. Your second example where "user_id": "e9604ef36d94a4ade7f394" is better because you have a key with a valid name which is not a data point. Commented Dec 5, 2019 at 23:17
  • Thanks @barrypicker! added the brackets, let's consider that I do it in the correct way you just mentioned. I can't make that update work! Commented Dec 5, 2019 at 23:20
  • 1
    OK, so you want to update a single sub document in the array? Or are you simply trying to inject the sub document into the array? Commented Dec 5, 2019 at 23:20
  • @barrypicker I'm trying to add a new user object to the array, if it's not present yet (by user_id) Commented Dec 5, 2019 at 23:24
  • I added an answer with a code snippet. Instead of having import statements I fully qualify each object for clarity. Please let me know if you have any questions... Commented Dec 5, 2019 at 23:39

2 Answers 2

1

I have a Java example program that I continually hack on to learn. My example may have bits that don't apply, but the basis for the question in here. Notice use of "$push"...

This assumes a record is available to query and push a new array item...

package test.barry;

public class Main {

        public static void main(String[] args) {
                com.mongodb.client.MongoDatabase db = connectToClusterStandAlone();
                InsertArrayItem(db);

                return;
        }


        private static void InsertArrayItem(com.mongodb.client.MongoDatabase db) {
                System.out.println("");
                System.out.println("Starting InsertArrayItem...");

                com.mongodb.client.MongoCollection<org.bson.Document> collection = db.getCollection("people");

                com.mongodb.client.MongoCursor<org.bson.Document> cursor = collection.find(com.mongodb.client.model.Filters.eq("testfield", true)).sort(new org.bson.Document("review_date", -1)).limit(1).iterator();

                if(cursor.hasNext()) {
                        org.bson.Document document = cursor.next();
                        Object id = document.get("_id");

                        System.out.println("Selected Id: " + id.toString());

                        org.bson.Document newDocument = new org.bson.Document("somekey", "somevalue");

                        collection.findOneAndUpdate(
                                com.mongodb.client.model.Filters.eq("_id", id),
                                new org.bson.Document("$push", new org.bson.Document("myarray", newDocument))
                        );  
                }   


                System.out.println("Completed InsertArrayItem.");
        }

        private static com.mongodb.client.MongoDatabase connectToClusterStandAlone() {
                // STANDALONE STILL REQUIRES HOSTS LIST WITH ONE ELEMENT...
                // http://mongodb.github.io/mongo-java-driver/3.9/javadoc/com/mongodb/MongoClientSettings.Builder.html

                java.util.ArrayList<com.mongodb.ServerAddress> hosts = new java.util.ArrayList<com.mongodb.ServerAddress>();
                hosts.add(new com.mongodb.ServerAddress("127.0.0.1", 27017));

                com.mongodb.MongoCredential mongoCredential = com.mongodb.MongoCredential.createScramSha1Credential("testuser", "admin", "mysecret".toCharArray());

                com.mongodb.MongoClientSettings mongoClientSettings = com.mongodb.MongoClientSettings.builder()
                        .applyToClusterSettings(clusterSettingsBuilder -> clusterSettingsBuilder.hosts(hosts))
                        .credential(mongoCredential)
                        .writeConcern(com.mongodb.WriteConcern.W1)
                        .readConcern(com.mongodb.ReadConcern.MAJORITY)
                        .readPreference(com.mongodb.ReadPreference.nearest())
                        .retryWrites(true)
                        .build();

                com.mongodb.client.MongoClient client = com.mongodb.client.MongoClients.create(mongoClientSettings);
                com.mongodb.client.MongoDatabase db = client.getDatabase("test");

                return db;
        }
}

Example document after running twice...

{
    "_id" : ObjectId("5de7f472b0ba4011a7caa59c"),
    "name" : "someone somebody",
    "age" : 22,
    "state" : "WA",
    "phone" : "(739) 543-2109",
    "ssn" : "444-22-9999",
    "testfield" : true,
    "versions" : [
        "v1.2",
        "v1.3",
        "v1.4"
    ],
    "info" : {
        "x" : 444,
        "y" : "yes"
    },
    "somefield" : "d21ee185-b6f6-4b58-896a-79424d163626",
    "myarray" : [
        {
            "somekey" : "somevalue"
        },
        {
            "somekey" : "somevalue"
        }
    ]
}

For completeness here is my maven file...

Maven POM File...

<project
    xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>test.barry</groupId>
    <artifactId>test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>test</name>
    <url>http://maven.apache.org</url>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${basedir}</outputDirectory>
                            <finalName>Test</finalName>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>test.barry.Main</mainClass>
                                </transformer>
                            </transformers>
                            <createDependencyReducedPom>false</createDependencyReducedPom>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongo-java-driver</artifactId>
            <version>3.10.1</version>
        </dependency>
    </dependencies>
</project>
Sign up to request clarification or add additional context in comments.

11 Comments

Great answer, thanks! But little problem, I can't user findOneAndUpdate method as it cant get resolved: Cannot resolve method 'findOneAndUpdate(org.bson.conversions.Bson, org.bson.Document)'
@Upsilon42 - are you saying this does not compile, or are you integrating into your code and it does not find the method?
It cannot compile, because method is not found :)
I know there is a lot of examples floating about using the old driver client. This example is using the 3.10 driver and most recent client. MongoDB now has driver 3.11 released for general use. I have compiled this file via mvn package and test run with the command java -jar Test.jar and I evaluated the database to ensure it worked as expected.
@Upsilon42 - I cannot tell by your code example what type 'collection' is.
|
1

I have a sample document and Java code (using MongoDB Java Driver 3.9.0) to update the users array.

MongoDB Enterprise > db.test.find()
{
        "_id" : 1,
        "index" : "999",
        "users" : [
                {
                        "user11" : {
                                "fld1" : "abcde"
                        }
                },
                {
                        "user22" : {
                                "fld1" : "xyz123"
                        }
                }
        ]
}


Java Code:

import org.bson.Document;
import org.bson.conversions.Bson;
import com.mongodb.client.result.UpdateResult;
import static com.mongodb.client.model.Updates.*;
import static com.mongodb.client.model.Filters.*;
import com.mongodb.client.*;

public class Testing9 {

    public static void main(String [] args) {

        MongoClient mongoClient = MongoClients.create("mongodb://localhost/");
        MongoDatabase database = mongoClient.getDatabase("users");
        MongoCollection<Document> collection = database.getCollection("test");

        String user = "user99"; // new user to be added to the array
        Bson userNotExistsFilter = exists(("users." + user), false);
        Bson idFilter = eq("_id", new Integer(1));
        Document newUser = new Document(user, new Document("fld1", "some_value"));
        Bson pushUser = push("users", newUser);

        UpdateResult result = 
            collection.updateOne(and(idFilter, userNotExistsFilter), pushUser);

        System.out.println(result);
    }
}


Result:

Querying the collection shows the updated array field users with the new user "user99":

MongoDB Enterprise > db.test.find().pretty()
{
        "_id" : 1,
        "index" : "999",
        "users" : [
                {
                        "user11" : {
                                "fld1" : "abcde"
                        }
                },
                {
                        "user22" : {
                                "fld1" : "xyz123"
                        }
                },
                {
                        "user99" : {
                                "fld1" : "some_value"
                        }
                }
        ]
}



Shell Query:

This is the equivalent update query from the mongo shell:

db.test.updateOne(
  { _id: 1, "users.user99": { $exists: false} },
  { $push: { users: { user99: { fld1: "some_value" } } } }
)

The collection's array will be added with the following document:

{
  "user99" : {
      "fld1" : "some_value"
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.