3

I am trying to insert a document with a sequence number, in one transaction, from java.

Something similar to this:

function getNextSequence(name) {
    var ret = db.counters.findAndModify(
        {
            query: { _id: name },
            update: { $inc: { seq: 1 } },
            new: true
        }
    );

    return ret.seq;
}
collection.insert({
    number: getNextSequence("userid"),
    name: "Some Name"
});

Is it possible to do this from java? Preferably with the official java driver.

4 Answers 4

5

Following the documentation for creating an Auto-Incrementing Sequence Field, we adapt it to be used in Java with the Java MongoDB driver.

Example implementation:

import java.net.UnknownHostException;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;

public class TestAutoIncrement {

private final static String DB_NAME = "MyTestDB";
private final static String TEST_COLLECTION = "testCollection";
private final static String COUNTERS_COLLECTION = "countersCollection";

public static DBCollection testCollection;
public static DBCollection countersCollection;

public static void main(String[] args) {

    try {
        MongoClient mongoClient = new MongoClient();
        DB database = mongoClient.getDB(DB_NAME);
        testCollection = database.getCollection(TEST_COLLECTION);
        countersCollection = database.getCollection(COUNTERS_COLLECTION);
    } catch (UnknownHostException e) {
        e.printStackTrace();
    }

    if (countersCollection.count() == 0) {
        createCountersCollection();
    }

    createTestCollection();
}

public static void createCountersCollection() {

    BasicDBObject document = new BasicDBObject();
    document.append("_id", "userid");
    document.append("seq", 0);
    countersCollection.insert(document);
}

public static Object getNextSequence(String name) {

    BasicDBObject searchQuery = new BasicDBObject("_id", name);
    BasicDBObject increase = new BasicDBObject("seq", 1);
    BasicDBObject updateQuery = new BasicDBObject("$inc", increase);
    DBObject result = countersCollection.findAndModify(searchQuery, null, null,
            false, updateQuery, true, false);

    return result.get("seq");
}

public static void createTestCollection() {

    BasicDBObject document = new BasicDBObject();
    document.append("_id", getNextSequence("userid"));
    document.append("name", "Sarah");
    testCollection.insert(document);

    document = new BasicDBObject();
    document.append("_id", getNextSequence("userid"));
    document.append("name", "Bob");
    testCollection.insert(document);

    document = new BasicDBObject();
    document.append("_id", getNextSequence("userid"));
    document.append("name", "Alex");
    testCollection.insert(document);
  }

}

Special attention must be paid to the findAndModify method. In the Java MongoDB driver (2.12.4), the method is available with 4 different signatures.
You must use one which lets you pass a query object, update object and returnNew boolean (which has to be set to true).

That's because, according to documentation:
By default, the returned document does not include the modifications made on the update. To return the document with the modifications made on the update, use the new option.

We need to return the document with the modifications made on the update.

Sign up to request clarification or add additional context in comments.

Comments

2

You cannot perform this in one transaction, and even your javascript example performs a findAndModify before performing the insert.

If you're looking to insert documents into a collection with an increasing count of documents from that collection you can use the count method and add 1.

    final DBCollection col = db.getCollection("myCollection");
    col.insert(new BasicDBObject("number", col.count() + 1));

Or by using a separate "counters" collection with a findAndModify() in lieu of count()

Comments

1

Try this:

DBCollection collection = database.getCollection("testCollection");
// create an increment query
DBObject modifier = new BasicDBObject("counter", 1);
DBObject incQuery = new BasicDBObject("$inc", modifier);
// create a search query
DBObject searchQuery = new BasicDBObject("name", "someName");
// increment a counter value atomically
DBObject res = collection.findAndModify(searchQuery, incQuery);

1 Comment

This will update the same object, i need something that inserts new objects were one field is incremented by one for each new object. they should look like this {name:"name", number:1},{name="name", number:2},{name="someothername",number:3}
1

just as Alex wrote but this code is appropriate for 3.x versions

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

public class TestAutoIncrement {

     private final static String DB_NAME = "MyTestDB";
     private final static String TEST_COLLECTION = "testCollection";
     private final static String COUNTERS_COLLECTION = "countersCollection";

     private static MongoCollection<Document> testCollection;
     private static MongoCollection<Document> countersCollection;

public static void main(String[] args) {

    MongoClient mongoClient = new MongoClient();
    MongoDatabase database = mongoClient.getDatabase(DB_NAME);
    testCollection = database.getCollection(TEST_COLLECTION);
    countersCollection = database.getCollection(COUNTERS_COLLECTION);

    if (countersCollection.count() == 0) {
        createCountersCollection();
    }

    createTestCollection();
    mongoClient.close();
}

public static void createCountersCollection() {

    Document document = new Document();
    document.append("_id", "userid");
    document.append("seq", 1);
    countersCollection.insertOne(document);
}

public static Object getNextSequence(String name) {

    Document searchQuery = new Document("_id", name);
    Document increase = new Document("seq", 1);
    Document updateQuery = new Document("$inc", increase);
    Document result = countersCollection.findOneAndUpdate(searchQuery, updateQuery);

    return result.get("seq");
}

public static void createTestCollection() {

    Document document = new Document();
    document.append("_id", getNextSequence("userid"));
    document.append("name", "Dinah");
    testCollection.insertOne(document);

    document = new Document();
    document.append("_id", getNextSequence("userid"));
    document.append("name", "Jonny");
    testCollection.insertOne(document);

    document = new Document();
    document.append("_id", getNextSequence("userid"));
    document.append("name", "Brody");
    testCollection.insertOne(document);
}

}

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.