Java Spring Boot embedded MongoDB doesn't trigger TTL removal - java

I am trying to test MongoDB TTL functionality for short-lived collections. Using #Indexed annotation on field like this:
#Indexed(name = "deleteAt", expireAfterSeconds = 5)
private Date deleteAt;
In constructor I initialise deleteAt to this.deleteAt = new Date() and I expect after inserting my Document to Mongo that after it's TTLManager will run this collection will be removed. But It is not being removed even waiting for a few minutes doesn't help. I ran db.serverStatus().metrics.ttl in mongo shell and it returned:
[
{
"deletedDocuments": 0,
"passes": 8
}
]
And command db.adminCommand({getParameter:1, ttlMonitorEnabled: 1}) returns:
[
{
"ok": 1,
"ttlMonitorEnabled": true
}
]
Is something wrong with my code ? Or it is because of embedded mongo doesn't support this, is it possible to configure embedded mongo so it would work ?
I am using https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo for embedded MongoDB with default settings.

It's only MongoDB server (mongod) feature
A background thread in mongod reads the values in the index and removes expired documents from the collection.
https://docs.mongodb.com/manual/core/index-ttl/#delete-operations
Embedded MongoDB framework "simulates" mongod process with MongodProcess class only to deploy a basic embedded server.
https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo/blob/master/src/main/java/de/flapdoodle/embed/mongo/MongodProcess.java

Related

Performing update using #Query via Spring Data MongoDB

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

AzureDocumentDB MongoDB protocol support: Failing to create TTL index

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.

Mongo DB, Java Mongo API, how to add hint into aggregate command

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

Generate random number within a range (0-100k) in a cluster environment

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.

Inserting data in Mongo DB using java and retrieve the data from Mongo DB using javascript

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

Categories

Resources