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.
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.
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()
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);
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);
}
}