MongoTemplate insert status - java

I want to create a DAO where I save users to my database. They should have unique logins and it's a little problematic as mongo db don't have transactions. I have a class with users that looks like this :
#Document(collection = "users")
public class User {
#Id
private String id;
#Indexed(unique = true)
private String username;
... }
and in my DAO I want to save new user
mongoTemplate.insert(user);
but how can I get the result to send response to my frontend whether user creation was successfull ?

The API will throw org.springframework.dao.DuplicateKeyException when unique index is violated.
Sample Code:-
try {
mongoOperations.insert(order);
} catch (DuplicateKeyException de) {
de.printStackTrace();
}
Exception Message when unique index is violated:-
org.springframework.dao.DuplicateKeyException: { "serverUsed" : "127.0.0.1:27017" , "ok" : 1 , "n" : 0 , "err" : "E11000 duplicate key error collection: localhost.order index: user_1 dup key: { : \"good\" }" , "code" : 11000}; nested exception is com.mongodb.MongoException$DuplicateKey: { "serverUsed" : "127.0.0.1:27017" , "ok" : 1 , "n" : 0 , "err" : "E11000 duplicate key error collection: localhost.order index: user_1 dup key: { : \"good\" }" , "code" : 11000}

Related

How to create a Mongodb Distinct search with a filter?

I was looking to create a distinct search in a MongoDB collection with a filter condition.
The collection is alertStatus with the following format:
{ 'id' : 0, 'group' : "groupe1", 'state' : "PENDING" }
{ 'id' : 1, 'group' : "groupe2", 'state' : "PENDING" }
{ 'id' : 2, 'group' : "groupe3", 'state' : "DONE" }
{ 'id' : 3, 'group' : "groupe2", 'state' : "PENDING" }
I want the list of different groups where the state is "PENDING"
Here is a working solution for Java/SpringBoot :
#Autowired
protected MongoTemplate mongoTemplate;
DistinctIterable<String> groups = mongoTemplate.getCollection("alertStatus")
.distinct("group",String.class)
.filter(new Document("state","PENDING"));
for ( String g : groups) {
log.info(g);
}
If someone has a solution using JPA, please let me know.

MongoDB error on update method during multithreading

i'm working with Apache Storm and i want to write on a MongoDB database but, sometimes, it throws an exception of
Caused by: com.mongodb.MongoException$DuplicateKey: { "serverUsed" : "127.0.0.1:27017" , "ok" : 1 , "n" : 0 , "updatedExisting" : false , "err" : "E11000 duplicate key error collection: TesiMarco.UserPostNew_Hampshire index: _id_ dup key: { : \"mainelyinspired\" }" , "code" : 11000}
while using parallelism option. In particular my bolt was executing:
public void execute(Tuple input, BasicOutputCollector collector) {
String user=input.getString(0);
DBObject query=new BasicDBObject("_id",user);
DBObject toUpdate=new BasicDBObject("$inc",new BasicDBObject("numeroPost",1));
collection.update(query,toUpdate,true,false);
}
but it finds duplicated error on key. How can i execute this part multithreading?

Mongodb QueryByExample findOne

Some other process inserts documents into mongo collection and below is the sample data
{ "_id" : ObjectId("597b89c8da52380b04ee6948"), "_class" : "com.test.mongo", "clientId" : "CAQ123999", "isValid" : false, "isParent" : true }
{ "_id" : ObjectId("597b89c8da52380b04ee6949"), "_class" : "com.test.mongo", "clientId" : "CAQ123999", "isValid" : false, "isParent" : true }
{ "_id" : ObjectId("597b89c8da52380b04ee6950"), "_class" : "com.test.mongo", "clientId" : "CAQ123998", "isValid" : true, "isParent" : true }
{ "_id" : ObjectId("597b89c8da52380b04ee6951"), "_class" : "com.test.mongo", "clientId" : "CAQ123997", "isValid" : true, "isParent" : false }
I'm trying to grab one record for the clientId, using QueryByExampleExecutor.
Here is my model
package com.test.cfp.model;
public class TFSModel {
private String clientId;
private boolean isValid;
private boolean isParent;
...
}
Here is the code to build the example:
TFSModel tfs = new TFSModel();
tfs.setClientId(CAQ123999);
tfs.setValid(false);
tfs.setParent(true);
ExampleMatcher matcher =ExampleMatcher.matching().withIgnoreNullValues().withIgnorePaths("_id","_class");
Example<TFSModel > example = Example.of(tfs,matcher);
TFSModel oneTfsRecord = tflsRepository.findOne(example);
This is not working , below is the generated query
findOne using query: { "isValid" : false , "isParent" : true , "clientId" : "CAQ123999" , "_class" : { "$in" : [ "com.test.cfp.model.TFSModel"]}} in db.collection: returns.tfs;
Obviously the _class has the different package than the one in the mongo collection. How can I tell mongo to build a query without _class. I tried withIgnoredPaths and its not working.
MongoExampleMapper inspects the probe type and writes type restrictions according to known types in MappingContext. Types assignable to the probe get included in the $in operator.
class One {
#Id String id;
String value;
// ...
}
class Two extends One {
// ...
}
One probe = new One();
probe.value = "firefight";
Example<One> example = Example.of(probe, ExampleMatcher.matchingAny());
{
value: firefight,
_class: { $in : [ "com.example.One" , "com.example.Two" ] }
}
This behavior cannot be altered by using .withIgnorePaths() as the _class specifier is not part of the domain model. Please file an issue in jira.spring.io if you think this should be considered.
Looking at the provided sample data from the mongo collection you provided the _class attribute is not matching your domain type and therfore cannot be loaded.

mongo + spring data + aggragate sum

I am looking for a solution without spring data. My project requirement is to do without spring data.
To calculate the sum using aggregate function by mongo command, able to get output. But same by using spring data getting exception.
Sample mongo query :
db.getCollection('events_collection').aggregate(
{ "$match" : { "store_no" : 3201 , "event_id" : 882800} },
{ "$group" : { "_id" : "$load_dt", "event_id": { "$first" : "$event_id" }, "start_dt" : { "$first" : "$start_dt" }, "count" : { "$sum" : 1 } } },
{ "$sort" : { "_id" : 1 } },
{ "$project" : { "load_dt" : "$_id", "ksn_cnt" : "$count", "event_id" : 1, "start_dt" : 1, "_id" : 0 } }
)
Same thing done in java as,
String json = "[ { \"$match\": { \"store_no\": 3201, \"event_id\": 882800 } }, { \"$group\": { \"_id\": \"$load_dt\", \"event_id\": { \"$first\": \"$event_id\" }, \"start_dt\": { \"$first\": \"$start_dt\" }, \"count\": { \"$sum\": 1 } } }, { \"$sort\": { \"_id\": 1 } }, { \"$project\": { \"load_dt\": \"$_id\", \"ksn_cnt\": \"$count\", \"event_id\": 1, \"start_dt\": 1, \"_id\": 0 } } ]";
BasicDBList pipeline = (BasicDBList) JSON.parse(json);
System.out.println(pipeline);
AggregationOutput output = col.aggregate(pipeline);
exception is :
com.mongodb.CommandFailureException: { "serverUsed" : "somrandomserver/10.10.10.10:27001" , "errmsg" : "exception: pipeline element 0 is not an object" , "code" : 15942 , "ok" : 0.0}
Could someone please suggest how to use aggregate function with spring?
Try the following (untested) Spring Data MongoDB aggregation equivalent
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
MongoTemplate mongoTemplate = repository.getMongoTemplate();
Aggregation agg = newAggregation(
match(Criteria.where("store_no").is(3201).and("event_id").is(882800)),
group("load_dt")
.first("event_id").as("event_id")
.first("start_dt").as("start_dt")
.count().as("ksn_cnt"),
sort(ASC, previousOperation()),
project("ksn_cnt", "event_id", "start_dt")
.and("load_dt").previousOperation()
.and(previousOperation()).exclude()
);
AggregationResults<OutputType> result = mongoTemplate.aggregate(agg,
"events_collection", OutputType.class);
List<OutputType> mappedResult = result.getMappedResults();
As a first step, filter the input collection by using a match operation which accepts a Criteria query as an argument.
In the second step, group the intermediate filtered documents by the "load_dt" field and calculate the document count and store the result in the new field "ksn_cnt".
Sort the intermediate result by the id-reference of the previous group operation as given by the previousOperation() method.
Finally in the fourth step, select the "ksn_cnt", "event_id", and "start_dt" fields from the previous group operation. Note that "load_dt" again implicitly references an group-id field. Since you do not want an implicit generated id to appear, exclude the id from the previous operation via and(previousOperation()).exclude().
Note that if you provide an input class as the first parameter to the newAggregation method the MongoTemplate will derive the name of the input collection from this class. Otherwise if you don’t not specify an input class you must provide the name of the input collection explicitly. If an input-class and an input-collection is provided the latter takes precedence.

Update array element in JAVA Spring mongo

{
"_id" : ObjectId("55d42e3a0b21449d07f9a8a6"),
"status" : 1,
"billList" : [
{
"id" : 123,
"status" : 1
},
{
"id" : 234,
"status" : 1
},
......
{
"id" : xxx,
"status" : 0 // only the final record has status = 0
}
]}
I have many billList record and I want to update status of the final record from 0 to 1 but don't know the id of it.
{
"id" : xxx,
"status" : 0 // only the final record has status = 0
}
to
{
"id" : xxx,
"status" : 1
}
How can I use JAVA Spring to do that? Thank you!
Please have a try on below sample solution
MongoClient c = new MongoClient();
//to get your db (Please replace "yourDB" with your db name)
MongoDatabase db = c.getDatabase("yourDB");
//to get your collection (Please replace "yourColl" with your collection name)
MongoCollection<Document> yourColl = db.getCollection("yourColl");
//search result list to be return
List<Document> result = new ArrayList<Document>();
//to get final record from billList
yourColl.find().projection(new Document("billList", new Document("$slice",-1))).into(result);
//Based on your snippet given, assume there is only 1 document return and to get that document. You can put a loop here if there are more than 1 documents return and to be update
Document resultToUpdate = result.get(0);
//Update status
yourColl.updateOne(new Document("_id",resultToUpdate.get("_id")).append("billList.id", resultToUpdate.get("billList.id")), new Document("$set",new Document("billList.$.status",1)));

Categories