Cannot get custom document ID in Couchbase Lite - Android - java

I'm new in Couchbase Android. I use Couchbase Lite v1.1.0 to save my data local. But I facing with some problems when to do that. I googled, read document in Couchbase Lite and find all post in stackoverflow but I still not understand what I facing.
Here is my snippet demo code to save my data in database with custom id of document is index i:
cbManager=new Manager(new AndroidContext(context),
Manager.DEFAULT_OPTIONS);
cbDatabase=cbManager.getDatabase("my_db");
.....
for(int i=0; i<10; i++){
Document document=cbDatabase.getDocument(String.valueOf(i)); // This line I custom document with id i
Map<String,Object> docContent= new HashMap<String, Object>();
docContent.put("title", title);
docContent.put("firstName", firstName);
docContent.put("lastName", lastName);
try{
document.putProperties(docContent);
} catch (CouchbaseLiteException e){
Log.e(TAG, "Cannot write document to database", e);
}
}
And get all datas from Couchbase Lite:
Query allDocumentsQuery= cbDatabase.createAllDocumentsQuery();
QueryEnumerator queryResult=allDocumentsQuery.run();
for (Iterator<QueryRow> it=queryResult;it.hasNext();){
QueryRow row=it.next();
Document doc=row.getDocument();
String id=doc.getId(); // I get the id in here but the result is the default id (UUID):(
}
So, I have two questions:
When I query all documents from database (couchbase lite), the document is returned which the default id (UUID), Why it is not return my custom ID?
( means: Saving all the document to database which custom ids: 1, 2, 3 ......9. But the result of all documents when get from database have default ids: UUID, UUID,..., UUID. )
I dont understand Why I save the document in order but the return of all documents are not in order ? (because this reason make me custom id of document)
Please give me some advises or guide me on the best way to do this. Thank you all so much.

You need to add the _rev property to your map with the id as value.
Here's an excerpt from the documentation:
putProperties(Map<String, Object> properties)
Creates and saves a new Revision with the specified properties. To succeed the specified properties must include a '_rev' property whose value maches the current Revision's id.
So your code should look like this:
Map<String,Object> docContent= new HashMap<String, Object>();
docContent.put("_rev", String.valueOf(i));
docContent.put("title", title);
docContent.put("firstName", firstName);
docContent.put("lastName", lastName);

Related

How to test roll over feature in mongo db transactions

I am newbie to MongoDB i implemented transactional feature in one of my application, as per my requirements i need to persist data into different collections in the same database. Below is the code snippet for the same
In Tuple3 first element is database, second element is collection and third element is data i want to persist which is coming as json string which i am converting to bson document
ClientSession clientSession = mongoClient.startSession();
try {
clientSession.startTransaction(transactionOptions);
for (Tuple3<String, String, String> value: insertValues) {
MongoCollection<Document> collection = mongoClient
.getDatabase(insertValues.f0)
.getCollection(insertValues.f1);
Document data= Document.parse(insertValues.f2);
log.info(String.format("Inserting data into database %s and collection is %s", insertValues.f0, insertValues.f1));
collection.insertOne(clientSession, data);
clientSession.commitTransaction();
}
} catch (MongoCommandException | MongoWriteException exception) {
clientSession.abortTransaction();
log.error(String.format("Exception happened while inserting record into Mongo DB rolling back the transaction " +
"and cause of exception is: %s", exception));
} finally {
clientSession.close();
}
Below are transaction options i am using
TransactionOptions transactionOptions = TransactionOptions.builder().readConcern(ReadConcern.LOCAL).writeConcern(WriteConcern.W1).build();
Below is MongoClient method with MongoClientOptions i am taking Mongo DB Connection string as input to this method
public MongoClient getTransactionConnection(String connectionString) {
MongoClientOptions.Builder mongoClientOptions = new MongoClientOptions.Builder()
.readConcern(ReadConcern.LOCAL)
.writeConcern(WriteConcern.W1)
.readPreference(ReadPreference.primary())
.serverSelectionTimeout(120000)
.maxWaitTime(120000)
.connectionsPerHost(10)
.connectTimeout(120000);
MongoClientURI uri = new MongoClientURI(connectionString, mongoClientOptions);
return new MongoClient(uri);
}
Till here it is good and it is inserting data to three different collection under the specified database. But when i try to some negative scenario i am trying to throw exception in try block which ideally should rollback the data for that particular client session if any error happens.
I am trying to throw exception by using count variable which will increment and for if count value is equal to 1 i am throwing exception which should abort the transaction and rollback if any data is written to database but what i am seeing it is writing to one of the collection and throws exception after that stops the program but it is not rolling back the data written to collection actually. I am trying something like this below
ClientSession clientSession = mongoClient.startSession();
int count = 0;
try {
clientSession.startTransaction(transactionOptions);
for (Tuple3<String, String, String> value: insertValues) {
MongoCollection<Document> collection = mongoClient
.getDatabase(insertValues.f0)
.getCollection(insertValues.f1);
Document data= Document.parse(insertValues.f2);
log.info(String.format("Inserting data into database %s and collection is %s", insertValues.f0, insertValues.f1));
collection.insertOne(clientSession, data);
if(count == 1){
throw new MongoException("Aborting transaction.....");
}
count++;
clientSession.commitTransaction();
}
} catch (MongoCommandException | MongoWriteException exception) {
clientSession.abortTransaction();
log.error(String.format("Exception happened while inserting record into Mongo DB rolling back the transaction " +
"and cause of exception is: %s", exception));
} finally {
clientSession.close();
}
I am not sure where i am going wrong i am using Mongo DB version 4.0 deployed using Azure CosmosDB Api. Please help me in resolving this issue thanks in advance.
Cosmos DB does not have transaction support outside of a single partition (shard) of a single collection. This limitation exists regardless of API in use (in your case, MongoDB API). This is why you're not seeing the behavior you're expecting. Note: this is mentioned in the Cosmos DB MongoDB compatibility docs.
You'll need to come up with your own implementation for managing data consistency within your app.

Multi field updates in document in java mongodb

Below is my mongob document structure
{
"employee_id":"123",
"employee_name":"ABC",
"elements":[
{
"element_name":"Verification Id",
"element_value":"Test Address",
"element_status":"selected"
},
{
"element_name":"Reportees",
"element_value":["ABC","DEF"],
"element_status":"selected"
}
,
{
"element_name":"Countries",
"element_value":["China","USA"],
"element_status":"selected"
}
]
}
My input will be {"countries":["Russia","Japan"],"Verification Id":"license"}.
My requirement is to update the only the countries and Verification Id element values for the given employee id. Reportees should remain untouched.
What are the ways to achieve this using java mongodb.
I tried following approaches
1)
collection.updateMany(Filters.and(Filters.eq("employee_id", "123"),Filters.eq("elements.element_name", "Verification Id"))
,
Updates.combine(
Updates.set("elements.$.element_value", "license"),
Updates.set("elements.$.element_status", "changed"),
));
and
collection.updateMany(Filters.and(Filters.eq("employee_id", "123"),Filters.eq("elements.element_name", "Countries")))
,
Updates.combine(
Updates.set("elements.$.element_value", ["Russia","Japan"]),
Updates.set("elements.$.element_status", "changed"),
));
The disadvantage here is that I end up making 2 db calls. If more such parameters come as input, then the number of db calls to perform the update increases
2.)
List<DBObject> array = new ArrayList<DBObject>();
BasicDBObject bObj=new BasicDBObject();
bObj.put("element_name", "Countries");
bObj.put("element_value", ["Russia","Japan"]);
bObj.put("element_status", "changed");
BasicDBObject bObj1=new BasicDBObject();
bObj1.put("element_name", "Verification Id");
bObj1.put("element_value", "license");
bObj1.put("element_status", "changed");
array.add(bObj);
array.add(bObj1);
collection.updateMany(Filters.eq("employee_id", "123"),
Updates.combine(
Updates.set("elements", array)
));
The disadvantage is that it completly over writes the elements array and removes the array element "element_name":"Reportees".
PLease guide me further on this. PLease let me know the best way to update select fields based on different criteria.

How do i do a Save operation on a MongoDB collection using the Java driver?

I just switch over from Python, and need to continue my work with a MongoDB database. One particular task is to save an incoming document (in this case, a tweet) into a collection for archiving. A tweet could comes in multiple times, so I prefer to use save() over insert() since the former do not raise an error if the document already exists in the collection. But it seems the Java driver for MongoDB does not support the save operation. Am I missing something?
EDIT: for reference, i'm using this library 'org.mongodb:mongodb-driver:3.0.2'
Example code:
MongoCollection<Document> tweets = db.getCollection("tweets");
...
Document tweet = (Document) currentDocument.get("tweet");
tweets.insertOne(tweet);
The last line raise this error when the tweet already exists:
Exception in thread "main" com.mongodb.MongoWriteException: insertDocument :: caused by :: 11000 E11000 duplicate key error index: db.tweets.$_id_ dup key: { : ObjectId('55a403b87f030345e84747eb') }
Using the 3.x MongoDB Java driver you can use MongoCollection#replaceOne(Document, Document, UpdateOptions) like this:
MongoClient mongoClient = ...
MongoDatabase database = mongoClient.getDatabase("myDB");
MongoCollection<Document> tweets = db.getCollection("tweets");
...
Document tweet = (Document) currentDocument.get("tweet");
tweets.replaceOne(tweet, tweet, new UpdateOptions().upsert(true));
This will avoid the duplicate key error. However, this is not exactly the same as using DBCollection#save(DBObject), since it uses the whole Document as filter instead of just the _id field. To mirror the old save method, you would have to write something like this:
public static void save(MongoCollection<Document> collection, Document document) {
Object id = document.get("_id");
if (id == null) {
collection.insertOne(document);
} else {
collection.replaceOne(eq("_id", id), document, new UpdateOptions().upsert(true));
}
}

creating unique index in mongoDB

I am using a java program for mongo db insertion trying to create a unique index for a field. product_src is a field in my collection and I want to set it as unique index for avoiding the duplicate insertion. I am trying the following code but showing syntax error what is the problem with this.
DB db;
try {
sample = new MongoClient("myIP",PORT);
db = sample.getDB("client_mahout");
t = db.getCollection("data_flipkart_in_avoid_duplicate_checking");
System.out.println("enter the system ip");
db.t.ensureIndex({"product_src":1});
} catch (Exception e) {}
t is the collection. there is problem with line db.t.ensureIndex({"product_src":1});
Please give me a sample code how to create unique index in mongo DB
For future reference, the way to handle this in the Java Mongo driver v3.0+ is by:
public void createUniqueIndex() {
Document index = new Document("field", 1);
MongoCollection<Document> collection = client.getDatabase("db").getCollection("Collection");
collection.createIndex(index, new IndexOptions().unique(true));
}
You need to pass a DBObject to the ensureIndex() method.
db.t.ensureIndex(new BasicDBObject("product_src",1))
But, the ensureIndex method has been deprecated since version 2.12, you need to use createIndex() instead.
db.t.createIndex(new BasicDBObject("product_src",1));

Java MongoDB getting value for sub document

I am trying to get the value of a key from a sub-document and I can't seem to figure out how to use the BasicDBObject.get() function since the key is embedded two levels deep. Here is the structure of the document
File {
name: file_1
report: {
name: report_1,
group: RnD
}
}
Basically a file has multiple reports and I need to retrieve the names of all reports in a given file. I am able to do BasicDBObject.get("name") and I can get the value "file_1", but how do I do something like this BasicDBObject.get("report.name")? I tried that but it did not work.
You should first get the "report" object and then access its contents.You can see the sample code in the below.
DBCursor cur = coll.find();
for (DBObject doc : cur) {
String fileName = (String) doc.get("name");
System.out.println(fileName);
DBObject report = (BasicDBObject) doc.get("report");
String reportName = (String) report.get("name");
System.out.println(reportName);
}
I found a second way of doing it, on another post (didnt save the link otherwise I would have included that).
(BasicDBObject)(query.get("report")).getString("name")
where query = (BasicDBObject) cursor.next()
You can also use queries, as in the case of MongoTemplate and so on...
Query query = new Query(Criteria.where("report.name").is("some value"));
You can try this, this worked for me
BasicDBObject query = new BasicDBObject("report.name", "some value");

Categories