mongodb MongoTemplate withWriteConcern how? - mongodb

Service
session.startTransaction();
DAO
db.getCollection("test").withWriteConcern(WriteConcern.MAJORITY);
target.insertOne(session,contents);
Service
session.commitTransaction();
how to
MongoTemplate withWriteConcern???
I'm curious how to withWriteConcern from mongotemplate.

You can use the MongoTemplate's method setWriteConcern
to specify the write concern for your write action on the MongoDB collection.
From Spring-Data MongoDB documentation on WriteConcern:
10.4.3.
WriteConcern:
If it has not yet been specified through the driver at a higher level
(such as com.mongodb.MongoClient), you can set the
com.mongodb.WriteConcern property that the MongoTemplate uses for
write operations. If the WriteConcern property is not set, it defaults
to the one set in the MongoDB driver’s DB or Collection setting.
Another way of configuring the write concern on MongoTemplate is by using the WriteConcernResolver interface.
From Spring-Data MongoDB documentation on WriteConcernResolver:
10.4.4.
WriteConcernResolver:
For more advanced cases where you want to set different WriteConcern
values on a per-operation basis (for remove, update, insert, and save
operations), a strategy interface called WriteConcernResolver can be
configured on MongoTemplate. Since MongoTemplate is used to persist
POJOs, the WriteConcernResolver lets you create a policy that can map
a specific POJO class to a WriteConcern value...
MongoTemplate#setWriteConcernResolver
WriteConcernResolver

Related

how to implement multi-tenant using spring-data-mongodb

I am new to multi-tenancy with mongodb using spring-data-mongodb, we need to use spring-data-mongodb for rest APIs and scheduling tasks( we have more than one schedulers in our application) in the same code with thread-safe. Is autowiring mongoTemplate will make application thread safe as the same mongoTemplate will be accessed from Schedulers and APIs both. Please get me the good practice in such a situation.
Regards
Kris
MongoTemplate itself is thread-safe, i.e. you can call it from multiple threads at the same time, and it will work correctly, i.e. send the different requests correctly to MongoDB.
But that doesn't guarantee consistency: if the scheduler is running and executes multiple updates in the same task, an API call can possibly get some updated records and some other records that aren't updated yet.
By the way: multi-tenancy is having data from multiple organisational entities in the same database. I'm not sure how that links to your question, did you mean multi-threading?
If you use different databases, then you can't use an autowired MongoTemplate.
For autowiring, there must be a single instance, but since the database connection string is a dependency of a MongoTemplate, there must be a single database as well.
You could go for an approach where you do not auto-wire the MongoTemplate directly, but use some sort of factory pattern to create the correct MongoTemplate for the current tenant. See Making spring-data-mongodb multi-tenant for some examples. (It's an old question, but its answers get updated every now and then).
Or you could go with an infrastructural solution, and deploy separate instances of your application, one for each tenant, e.g. on Kubernetes.

Update MongoDB $jsonSchema with Spring Data

Spring Data documentation describes how to create collection with given $jsonSchema, and how to perform a validation query.
Is there a way to update $jsonSchema for an existing collection? MongoTemplate.createCollection() for an existing one results in MongoCommandException with error code 48 (collection exists), schema is not being updated.
Ok, looks like there is no ready-to-use method in Spring Data, but it is pretty simple to implement:
<T> void updateSchema(MongoTemplate template, Class<T> entityClazz, MongoJsonSchema schema) {
template.executeCommand(new Document(Map.of(
"collMod", template.getCollectionName(entityClazz),
"validator", schema.toDocument()
)));
}
Also keep in mind that default readWrite role is not enough, user needs to have collMod privilege.

How to dynamically create MongoTemplate instances, with credentials?

Prior to Spring Data MongoDB 1.9.0-RELEASE, I was able to create a MongoTemplate object as follows:
new MongoTemplate(client, dbName, credentials). Upon upgrading, this constructor no longer works, giving an error to use MongoCredential instead. However, there is no similar MongoTemplate constructor that uses MongoCredential. It appears that the only way to specify credentials now is when constructing the MongoClient object.
However, since my app is multitenant on the database level, this doesn't work because it does not allow for additional credentials to be added after construction (meaning MongoTemplates cannot be created dynamically). It also is not ideal because if any of the credentials in the list are bad, none of the database connections work, as opposed to just the one with bad credentials.
I also do not want to create a new MongoClient instance for each database. From what I understand, doing so would create a new connection for each database rather than letting MongoClient manage a connection pool, which is ultimately not sustainable since Mongo only allows a finite number of connections.
Do I have any options here besides continuing to use the outdated library?
What you can do is instantiate the MongoClient and cache it using a HashMap with some unique db identifier as key and mongoClient as value. Use that create MongoTemplate
What I ended up doing is creating a single user in the admin database that has access to all of the databases that I need (achieved via the roles array). I create one MongoClient, authorizing as that user against the admin database. Then I am able to create MongoTemplate objects dynamically without issue, because the user I'm authorized as hasreadWrite permissions on those databases.

Spring Data partial upsert not persisiting type information

I am using Spring Data with MongoDB to store very dynamic config data in a toolkit. These Config objects consist of a few organizational fields, along with a data field of type Object. On some instances of Config, the data object refers to a more deeply nested subdocument (such as "data.foo.bar" within the database. – this field name is set by getDataField() below). These Config objects are manipulated as they're sent to the database, so the storage code looks something like this:
MongoTemplate template; // This is autowired into the class.
Query query; // This is the same query which (successfully) finds the object.
Config myConfig; // The config to create or update in Mongo
Update update = new Update()
.set(getDataField(), myConfig.getData())
.set(UPDATE_TIME_FIELD, new Date())
.setOnInsert(CREATE_TIME_FIELD, new Date())
.setOnInsert(NAME_FIELD, myConfig.getName());
template.upsert(query, update, Config.class);
Spring recursively converts the data object into a DBObject correctly, but neither the data document nor any of its subdocuments have "_class" fields in the database. Consequentially, they do not deserialize correctly.
These issues seem quite similar to those previously reported in DATAMONGO-392 , DATAMONGO-407, and DATAMONGO-724. Those, however, have all been fixed. (I am using spring-data-mongodb 1.4.2.RELEASE)
Am I doing something incorrectly? Is there a possibility that this is a Spring issue?
Came across a similar issue. One solution is to write your own Converter for Config.class.

spring-data-mongodb. How can i dynamically create a database in mongo using spring-data-mongodb library?

spring-data-mongodb. How can i dynamically create a database in mongo using spring-data-mongodb library?
I am trying to use Spring-Mongodb-Data module for CRUD operations against Mongo database and going through examples and articles my assumption is that databasename should be pre-defined in spring context xml when defining MongoTemplate bean.
In my case I have an multi-tenant application that will accept requests over http and my application should create the mongodatabase on-the-fly and use the name provided in the input http request to create the database and then load the data into collection in the newly created database.
I am trying to figure out if there is a way to dynamically populate the databasename in MongoTemplate or MongoRepository without having to provide it in spring context.xml?
Please help me.
Thanks
-RK
Have you tried the following instead of going through the pre-defined spring context configuration.
MongoTemplate getMongoTemplate(Mongo mongo, String database) {
return new MongoTemplate(mongo, database);
}