mongodb - compound unique index using spring data not working - mongodb

I am trying to create unique compound index in mongodb using spring data.
But I see that the index is not created and the duplicate document is created in the DB.
My entity class:
#Document
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#CompoundIndexes(
#CompoundIndex(name = "daybook_index", def = "{'date' : 1, 'vehicleNumber' : 1}", unique = true)
)
public class Daybook {
private String date;
private String vehicleNumber;
private String unit;
}
I am using repository.insert() method to create the document.
When I see in mongo express I see only one index created on _id and the index defined in the entity class is not created.
Is it a bug in spring data or am I doing something wrong?
P.S.: I tried to delete the collection too before running the application but didn't help.

As of Spring Data MongoDB 3.0, automatic index creation is turned off by default.
To turn it on you might use the proper flag overriding the method from MongoConfigurationSupport:
public class MongoConfiguration extends AbstractMongoClientConfiguration {
.....
#Override
protected boolean autoIndexCreation() {
return true;
}
}
otherwise you might create the index with appropriate instructions.
mongoOperations.indexOps(Daybook.class).ensureIndex(new Index().on("date", Direction.ASC).on("vehicleNumber", Direction.ASC).unique());

As #Saxon mentioned:
Spring Data MongoDB 3.0, automatic index creation is turned off by default.
Instead of adding code, I am able to create the index by adding the spring data configuration in application.properties
spring.data.mongodb.auto-index-creation=true

Related

Java Spring Data MongoDB

I am using Spring data mongo with azure cosmos. My structure looks like below.
I have an Id field in my collection that is not annotated with #Id. I see both _id and id are in the DB but When I retrieve id field comes with the value is in _id.
#Document(collection = "mycollection")
class MyObject{
private String id;
...
}
public interface MyRepository extends MongoRepository<MyObject, Void> {
}
Used #Field("id") to tell spring data threat this field as is not as _id/pk field for mongo

$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

Spring boot / mongo wont create index with the index annotation

I have the following:
#Document(collection = "linkmetadata")
public class LinkMetaData {
#Indexed(unique = true)
private String url;
...
}
But whenever it creates the collection it doesn't create any index for the url field, it's like it just ignores the annotation. Any idea why this is?
Edit: no index is created upon insertion of data either. And when I try to fetch data for a specific url it throws an error that the url key is not unique if I entered the same url twice, but it doesn't care about inserting the unique key since there is no index..
use auto-index-creation: true in your application properties.Add billow line in your application.properties
spring.data.mongodb.auto-index-creation: true
I found the problem. I had another collection also with a url field marked as unqiue. I had to specify the name of the index on one of them otherwise it seems that it considered that the index already exists even though it was on two different collections
#Indexed(name = "meta_url_index_unique", unique = true)
private String url;
Edit: This answer was before the author updates his question
I believe you need to use the #Document annotation on top the class declaration
So your class should be
#Document
public class LinkMetaData {
#Indexed(unique = true)
private String url;
...
}
I Also had the same issue. The one that solved my issue was adding the index from the mongo db level
db.city.createIndex( { "name": 1 }, { unique: true } );

How to create an "unique" contraint in MongoDB through Hibernate OGM and JPA

I'm trying to define a unique constraint on a non-id field. The answer might seem obvious:
#Entity
#Table(uniqueConstraints=#UniqueConstraint(columnNames={"col1"}))
public class MyEntity { ... }
However, this is not working. I've checked the indexes in the collection through the mongo command line, but there is no trace of a unique index (only a _id_ index is being generated).
I have also tried with the #Index annotation without joy:
#Entity
#Table(indexes={ #Index(name = "myIndex", columnList="col1", unique = true) })
public class MyEntity { ... }
The #Column(unique = true) annotation doesn't have any effect either.
How can I get Hibernate OGM to create a unique index for this collection?
Thank you in advance,
Guillermo
Hibernate OGM does not yet consider this index/constraint meta-data for MongoDB. I've opened OGM-910 for tracking it.

Spring Data Mongo Repository update operation

I am using Spring Data Mongo repository for persisting my entities. The parent class of all entities looks like this:-
#Document
public abstract class AbstractEntity {
#Id
private String id;
#CreatedDate
private Date dateCreated;
#LastModifiedDate
private Date lastUpdated;
#Version
private Long version; // This is creating trouble while 'update' operation
}
This is how I configure Mongo repositorries and auditing:-
#Configuration
#EnableMongoRepositories(basePackages = { "x.y.z" })
#EnableMongoAuditing
#EnableAutoConfiguration
public class MongoRepositoryConfig {
}
I am able to save and 'UPDATE' my entities to Mongo until I don not include the #Version field in my entity for auditing.
PROBLEM
If I use the #Version auditing field in my entity class, while trying to update a entity/document using MongoRepository#save(entity) method I am getting following exception:-
Caused by: com.mongodb.MongoException$DuplicateKey: { "serverUsed" : "localhost:27017" , "ok" : 1 , "n" : 0 , "err" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.MENU_ITEM.$_id_ dup key: { : ObjectId('541ed581f39d6f87787067e3') }" , "code" : 11000}
at com.mongodb.CommandResult.getWriteException(CommandResult.java:88)
at com.mongodb.CommandResult.getException(CommandResult.java:79)
at com.mongodb.DBCollectionImpl.translateBulkWriteException(DBCollectionImpl.java:314)
at com.mongodb.DBCollectionImpl.insert(DBCollectionImpl.java:189)
at com.mongodb.DBCollectionImpl.insert(DBCollectionImpl.java:165)
at com.mongodb.DBCollection.insert(DBCollection.java:93)
at com.mongodb.DBCollection.insert(DBCollection.java:78)
at com.mongodb.DBCollection.insert(DBCollection.java:120)
at org.springframework.data.mongodb.core.MongoTemplate$8.doInCollection(MongoTemplate.java:900)
at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:410)
Why upsert operation is failing when the entity has #Version? From what I understand, the version field is used for optimistic locking while update operation.
The save save methods seems to be trying to do an insert operation instead of update. Is it expected behaviour with #Version?
<spring.data.mongo.version>1.6.0.RELEASE</spring.data.mongo.version>
Cleaning the Mongo database fixed the problem.
Before I added the #Version Long version, property in my domain class, I had few existing mongo documents in the collection without version property. This was causing the problem.
It seems you are trying to save a document on which version is not matching with the document in mongo collection. It is either not set or some old value is set as version. MongoDB uses #version for optimistic locking which means it matches the version of document in the database with the version on the entity which is being saved. It throws an error if there is a version mismatch.
Try below code and it should get you over this error.
public void updateUser(String userId, String password) {
//Before updating a document for specified userId, fetch the latest document from db
Login userFromDB = loginRepository.findOne(userId);
userFromDB.setPassword(password); //set the field to be updated
userRepository.save(userFromDB); //this will overwrite the document in database with new pwd
}
On saving, MongoDB will increment the Version number.