springdata MongoDB batch inserts with continueOnError option - mongodb

MongoDB supports a continueOnError option so that batch insert continues even if there is a failure in a single document insertion.
Is there a way to achieve this using spring-data version 1.3.3.RELEASE. I am using the MongoOperations class and I don't see an API that allows me to do this.
Thanks!!

You should set this through the writeConcern options for MongoTemplate
mongoTemplate.setWriteConcern(
new WriteConcern(<Your options>).continueOnErrorForInsert(true));
Alternately there should be a constructor for for WriteConcern that does this as well.
More specifically as a usage, I set a Bean in a config class:
public #Bean
MongoTemplate mongoTemplate() throws Exception {
MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory());
WriteConcern writeConcern = new WriteConcern(2);
writeConcern.continueOnErrorForInsert(true);
mongoTemplate.setWriteConcern(writeConcern);
return mongoTemplate;
}
And then later on, set up the operations:
MongoOperations mongoOperation = (MongoOperations) ctx.getBean("mongoTemplate");
Collection collection = new Collection() { ... }
mongoOperation.insert(collection,"collection"); // Uses the writeConcern options

Related

How to add default criteria to all the queries by default in mongo spring boot

I have a requirement to soft delete documents in a given MongoDB collection. For that, I use a boolean called deleted. So now when I am retrieving data from the database, I have to always mention taking the data where the deleted=false.
Eg:
public Organization findOrgById(String id) {
Query query = new Query();
Criteria criteria = Criteria.where(Constants.ENTITY_ID).is(id)
.and(Constants.DELETED).is(false);
query.addCriteria(criteria);
Organization res = mongoTemplate.findOne(query, Organization.class);
return res;
}
Is there a way to specify that always all the criteria to add deleted=false by default without mentioning it in the code itself?
In Hibernate core there is an annotation #Where but it is not working with mongo documents.
I think the best way to do this is extend the MongoTemplate class that will add your deleted=false condition to all Find queries.
Here is an example of how to do it with one method used to execute findOne queries:
public class ExtendedMongoTemplate extends MongoTemplate {
private static final Document DELETED_CRITERIA_DOC = Criteria.where(Constants.DELETED).is(false)
.getCriteriaObject();
#Override
protected <T> T doFindOne(
String collectionName,
Document query,
Document fields,
CursorPreparer preparer,
Class<T> entityClass) {
query.putAll(DELETED_CRITERIA_DOC);
return super.doFindOne(collectionName, query, fields, preparer, entityClass);
}
...
}
This method is called in the method doFindOne(Query query, Class<?> entityClass) (the last one delegates executing
Other methods to override are:
protected <S, T> List<T> doFind(String collectionName, Document query, Document fields,
Class<S> entityClass, CursorPreparer preparer);
protected <T> T doFindAndRemove(String collectionName, Document query, Document fields,
Document sort, #Nullable Collation collation, Class<T> entityClass);
protected <T> T doFindAndModify(String collectionName, Document query, Document fields, Document sort,
Class<T> entityClass, UpdateDefinition update, #Nullable FindAndModifyOptions options);
protected <T> T doFindAndReplace(String collectionName, Document mappedQuery, Document mappedFields,
Document mappedSort, com.mongodb.client.model.Collation collation, Class<?> entityType,
Document replacement, FindAndReplaceOptions options, Class<T> resultType);
These methods execute queries at low-level, so they accept BSON-documents with the query criteria, not Spring's criteria. If you do this, the Find-methods will add an additional criteria to all you queries.
You also can override methods findOne, find, findAndModify and so on in a similar manner, but there are a lot of these methods that all use doFind* methods. Thus overriding doFind* will lead to work with all Find-queries. And don't forget override also findById (it also uses doFindOne internally).
By the way, #Where annotation is from Hibernate, but Spring Data Mongo doesn't use them. It requires its own annotations to work with your entities.

$or operator with multiple expressions and multiple fields in an expression using Spring Data Reactive MonogoDB

In MongoDB, I can use $or[{key1:'value11', key2:'value12'}, {key1:'value21', key2:'value22'}, {key1:'value31', key2:'value32'}, ...] to query several documents which matches at least one of the expressions in the $or operator. Then how the thing can be done using Spring Data Reactive MonogoDB?
In particular, I define a entity class as:
#Document
public class MyDocument
{
#Id
private String id;
private String field1;
private String field2;
}
And then, the repository interface for the entity:
public interface MyDocumentRepository extends ReactiveMongoRepository<MyDocument, String>
The question now is how to define a method in MyDocumentRepository to query the documents with field1 and field2:
There seems no proper keywords to create a query method (findAllBy(field1AndField2)In???)
If using JSON-based Query Methods, I really do know how to complete the Cloze test...
#Query("{$or:[(:fields)]}
Flux<MyDocument> findAllBy????(Flux<???> fields)
Spring Data MongoDB has support for ReactiveMongoTemplate. In a repository, you can use this as a connection to MongoDB which can be used with #Autowire.
In ReactiveMongoTemplate you can create Criteria with and and or operation like
Query query = new Query();
query.addCriteria(
new Criteria().andOperator(
Criteria.where("field1").exists(true),
Criteria.where("field1").ne(false)
)
);
and this can be passed to MongoDB with the before created instance of ReactiveMongoTemplate
Flux<Foo> result = reactiveMongoTemplate.find(query, Foo.class);
Documentation for use of configuration of ReactiveMongoTemplate if needed can be found here

Complex mongodb query with Quarkus

I need to migrate a Spring Boot project to Quarkus. The project has been using Spring Data Mongodb for all the queries. Now I find it difficult to migrate complex queries.
One example is
public List<MyData> findInProgressData(MyConditions conditions) {
Query mongoQuery = new Query();
mongoQuery.addCriteria(Criteria.where("status").is(IN_PROGRESS));
mongoQuery.addCriteria(Criteria.where("location").is(conditions.getLocationCode()));
if (StringUtils.isNotBlank(conditions.getType())) {
mongoQuery.addCriteria(Criteria.where("type").is(conditions.getType()));
}
if (StringUtils.isNotBlank(conditions.getUserId())) {
mongoQuery.addCriteria(Criteria.where("userId").is(conditions.getUserId()));
}
mongoQuery.with(Sort.by(Sort.Direction.ASC, "createdAt"));
return mongoTemplate.find(mongoQuery, MyData.class);
}
How can I implement the conditional query with Quarkus?
You can probably try Panache with Mongodb.
You can pass Document into .find() method, In this object you can specify any criteria.
final Document document = new Document();
document.put("status","IN_PROGRESS");
...
result = MyData.find(document); // or MyDataRepository
But you'll need to adapt some of the code to Panache, which can be done either via extending PanacheEntity or PanacheEntityBase

Insert DBObject into MongoDB using Spring Data

I tried to insert the following DBObject into MongoDB using Spring Data:
BasicDBObject document = new BasicDBObject();
document.put("country", "us");
document.put("city", "NY");
mongoTemplate.insert(document);
where mongoTemplate is my Spring template (org.springframework.data.mongodb.core.MongoTemplate).
When executing, I get:
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: No Persitent Entity information found for the class com.mongodb.BasicDBObject
at org.springframework.data.mongodb.core.MongoTemplate.determineCollectionName(MongoTemplate.java:1747)
at org.springframework.data.mongodb.core.MongoTemplate.determineEntityCollectionName(MongoTemplate.java:1732)
at org.springframework.data.mongodb.core.MongoTemplate.insert(MongoTemplate.java:658)
My JSON would be dynamic at the end. So any idea how to provide these entity information dynamically ?
Or is there another way to insert raw JSON into Mongodb through Spring Data ?
You are confusing spring-data with normal mongo persistence using the java driver.
If you want to persist data to mongoDB directly using the java driver then you would use the BasicDBObject like you have shown except that you would not use the mongoTemaplate class to persist but rather the MongoClient class. So it would look like this:
MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
DB db = mongoClient.getDB( "mydb" );
BasicDBObject o = new BasicDBObject();
o.set......
coll.insert(o);
But if you are trying to persist a document using spring-data, then you need to create a java class to represent your document (eg: Person) and annotate this class with #Document(collection="person") and then use the mongoTemplate (which is a spring-data specific class to persist this entity. This is very similar to using JPA/hibernate.
So it would look something like this
#Document(collection="person")
public class Person {
private String fisrtName;
....
Relevant getters and setters
}
And then the persistence
Person p = new Person();
p.setFirstName("foo");
p.setLastName("bar");
....
mongoTemplate.save(p);
Another way to do this is to directly access the DBCollection object via the MongoTemplate:
DBObject company = new BasicDBObject();
...
DBCollection collection = mongoTemplate.getCollection("company");
collection.insert(company);
Another way to do it
Import statements
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import org.springframework.data.mongodb.core.MongoTemplate;
Member Variables
#Autowired MongoTemplate mongoTemplate;
MongoCollection<Document> collection;
#PostConstruct
public void init(){
collection = mongoTemplate.getCollection("company");
}
And then, the method
public void insertRawData(){
Document company = new Document(new HashMap()); // If you have to insert a hashMap
// otherwise you can add one-by-one using company.put("foo","bar")
collection.insertOne(company);
}

Capped collections using MongoDB and SpringData

I am trying to create a capped collection for logging using mongoTemplate. However my collection size is growing beyond the size I passed as arguments. Can anyone please help with this.
public synchronized MongoTemplate getTemplate() {
if (template == null) {
Mongo mongo = null;
mongo = new Mongo(addrs);
template = new MongoTemplate(mongo, this.dbName);
if(!template.collectionExists(HttpRequestEntity.class)){
CollectionOptions options = new CollectionOptions(4,4,true);
template.createCollection(HttpRequestEntity.class, options);
}
}
return template;
}
For saving I am calling save on this template instance
getTemplate().save(entity);
Got it working after I deleted the collection from mongo console. I guess it was use old meta data as template.collectionExists(HttpRequestEntity.class) was returning true.