i wanted to do a direct update to mongodb and setting someflag to either true or false for my use case. To be effecient i do not want to query all documents and set the someflag and save it back to db. i just want to directly update it on db just like when doing update on mongodb terminal.
Here is the sample document. NOTE: these documents can number from 1 ~ N so i need to handle efficiently big datas
{
_id: 60db378d0abb980372f06fc1
someid: 23cad24fc5d0290f7d5274f5
somedata: some data of mine
flag: false
}
Currently im doing an #Query method on my repository
#Query(value ="{someid: ?0}, {$set: {flag: false}}")
void updateFlag(String someid)
Using the above syntax, it doesnt work, i always get an exception message below;
Failed to instantiate void using constructor NO_CONSTRUCTOR with
arguments
How do i perform a direct update effeciently without querying all those document and updating it back to db?
Use the BulkOperations class (https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/BulkOperations.html)
Sample codes:
Spring Data Mongodb Bulk Operation Example
I'm currently using Spring Data MongoDB to abstract MongoDB operations, and using an Azure DocumentDB database with MongoDB protocol support. I've also run into this using the latest MongoDB Java driver by itself.
There is an issue with setting a TTL index in this process.
I'm receiving the following exception.
`Caused by: com.mongodb.CommandFailureException: { "serverUsed" : "****-****-test.documents.azure.com:****" , "_t" : "OKMongoResponse" , "ok" : 0 , "code" : 2 , "errmsg" : "The 'expireAfterSeconds' option has invalid value. Ensure to provide a nonzero positive integer, or '-1'` which means never expire." , "$err" : "The 'expireAfterSeconds' option has invalid value. Ensure to provide a nonzero positive integer, or '-1' which means never expire."}
at com.mongodb.CommandResult.getException(CommandResult.java:76)
at com.mongodb.CommandResult.throwOnError(CommandResult.java:140)
at com.mongodb.DBCollectionImpl.createIndex(DBCollectionImpl.java:399)
at com.mongodb.DBCollection.createIndex(DBCollection.java:597)
This is a simple representation of the POJO that I'm using.
public class Train{
#JsonProperty
private String id;
#JsonProperty("last_updated")
#Indexed(expireAfterSeconds = 1)
private Date lastUpdated;
// Getters & Setters
.
.
.
}
This was my initial approach of initializing the index (via the #Indexed annotation).
I've also attempted to initialize the index via:
mongoTemplate.indexOps(collection.getName())
.ensureIndex(new Index("last_updated", Sort.Direction.DESC)
.expire(1, TimeUnit.SECONDS));
Both ways of setting the index throw that same execption.
I've also seen an error saying that it can only be done on the '_ts' field. I think this is due to Azure DocumentDB using the '_ts' field for it's own TTL operation. So I've tried the following with the same results:
Added a new field, Long '_ts', to the pojo and tried with the annotation.
Attempted to set the index via the ensureIndex method with '_ts' field.
Did the same things above but changing the type of '_ts' to Date.
I'm new to these technologies (DocumentDB and MongoDB), so I'm probably missing something obvious.
Any thoughts?
Revisiting my question I had posted a while back to reply with the solution that I figured out.
Note that DocumentDB has been renamed to CosmosDB since I posted this question.
There was an issue with type casting in either the Spring framework or the CosmosDB/DocumentDB platform side. Despite documentation saying it needs an integer, you actually need to pass it a double value.
I'm using something along the lines of the following and it works
dcoll.createIndex(new BasicDBObject("_ts", 1)
, new BasicDBObject("expireAfterSeconds", 10.0));
This works for me.
db.coll.createIndex( { "_ts": 1 }, { expireAfterSeconds: 3600 } )
Using Spring Boot and Spring Data in a ContextListener:
private final MongoTemplate mongoTemplate;
#EventListener(ContextRefreshedEvent.class)
public void ensureIndexes() {
mongoTemplate.indexOps(YourCollection.class)
.ensureIndex(
new Index()
.on("_ts", Sort.Direction.ASC)
.expire(30, TimeUnit.SECONDS)
);
}
The Azure console is a little confusing in the "Settings" options for the collection, it says "To enable time-to-live (TTL) for your collection/documents, create a TTL index" - it will say this even if you do already have such an index created.
Confirmed working January 2023 with Spring Boot 2.7.6 and Azure CosmosDB.
According to the blog DocumentDB now supports Time-To-Live (TTL) & the section Setting TTL on a document of the offical tutorial Expire data in DocumentDB collections automatically with time to live, the TTL setting on Azure DocumentDB is different from MongoDB, although Azure support do the operater on DocumentDB via MongoDB drive & spring-data in Java.
The TTL should be defined as a property on DocumentDB to set a nonzero positive integer value, so please try to change your code as below.
public class Train{
#JsonProperty
private String id;
#JsonProperty("last_updated")
private Date lastUpdated;
/*
* Define a property as ttl and set the default value 1.
*/
#JsonProperty("ttl")
private int expireAfterSeconds = 1;
// Getters & Setters
.
.
.
}
Hope it helps. Any concern, please feel free to let me know.
Update:
Notice the below content at https://learn.microsoft.com/en-us/azure/documentdb/documentdb-time-to-live#configuring-ttl.
By default, time to live is disabled by default in all DocumentDB collections and on all documents.
So please first enable the feature TIME TO LIVE on Azure portal as the figure below, or follow the above link to enable it programmatically.
I stuck with Mongo with $hint command.
I have collection and i had indexed this collection. But the problem is, I query collection with Aggregate framework, but I want temporary disable Indexing, so I use hint command like this:
db.runCommand(
{aggregate:"MyCollectionName",
pipeline:[{$match : {...somthing...},
{$project : {...somthing...}}]
},
{$hint:{$natural:1}}
)
Please Note that I use {$hint:{$natural:1}} to disable Indexing for this query,
I have run SUCCESSFULLY this command on MongoDB command line. But I don't know how to map this command to Mongo Java Api (Java Code).
I used lib mongo-2.10.1.jar
Currently you can't - it is on the backlog - please vote for SERVER-7944
I have to generate random number within a range (0-100.000) in a cluster environment (many stateless Java based app servers + Mongodb) - so every user request will get some unique number and will maintain it in the next few requests.
As I understand, I have two options:
1. have some number persisted in mongo and incrementAndGet it - but it's not atomic - bad choice.
2. Use Redis - it's atomic and support counters.
3. Any idea? Is it safe to use UUID and set a range for it ?
4. Hazelcast ?
Any other though?
Thanks
I would leverage the existing MongoDB infrastructure and use the MongoDB findAndModify command to do an atomic increment and get operation.
For the shell the command would look like.
var result = db.ids.findAndModify( {
query: { _id: "counter" },
sort: { rating: 1 },
new : true,
update: { $inc: { counter: 1 } },
upsert : true
} );
The 'new : true' returns the document after the update. Upsert creates the document if it is missing.
The 10gen supported driver and the Asynchronous Driver both contain helper methods/builders for the find and modify command.
I am new to Mongo DB can we insert the data in java and retrieve the data from Mongo DB using java script?
Please suggest.
Take a look into mongodb quick start
Take a look into mongodb java tutorial. Here you can find how to connect/query/update mongodb.
To retrieve data from mongodb via javascript create some service layer (it can be simple rest api) that will return data in json format for example.
Javascript way of printing output of MongoDB query to a file
1] create a javascript file
test.js
cursor = db.printShardingStatus();
while(cursor.hasNext()){
printjson(cursor.next());
}
2] run
mongo admin --quiet test.js > output.txt