MongoTemplate findAndModify get updated document count - java

I'm using MongoTemplate to implement a method that can update multiple documents according to the query, and return the updated document count.
When I was using MySQL, update method usually return the updated data count as default, so I'm wondering how can I get the same thing in mongo?
Also, using the findAndModify because I want the function to be multi-thread-safe.
Please help...

findAndModify updates only one document instead in MongoTemplate we have updateMulti which updates multiple document and return a writeResult which can tell you how many documents were updated
/**
* finds the elements based on query and modifies it
*
* #param query
* #param update
* #param clazz
* #return
* #throws MeowException
*/
protected <T> WriteResult modifyAll(final Query query, final Update update, final Class<T> clazz) throws MeowException{
try{
return getMongoTemplate().updateMulti(query, update, clazz);
}catch(Exception ex){
throw new MeowException(ex).withParam("query", query).withParam("update", update).withParam("class", clazz).logToFile("Exception in modifyAll");
}
}
This can be called as
WriteResult result = modifyAll(query, update, Kitten.class);
logger.error("document updated count :"+result.getN());
Hope it helps.

Related

spring-session-data-redis: about the SaveMode.ON_GET_ATTRIBUTE

I find the is just to be used in the method of org.springframework.session.data.redis.RedisIndexedSessionRepository.RedisSession#getAttribute
In my opinion, getAttribute has not function, because the cached is got form redis ather through SessionRepositoryFilter and the DispacthServlet flush session when invoke doService , and back to SessionRepositoryFilter save the RedisSession' delta to redis.
so getAttribute form cached is equal with form redis, and getAttribute will put the key-value to delta in the SaveMode.ON_GET_ATTRIBUTE and has the Attribute.
So it maybe put the some key-value back to redis.I really unkown why spring write that.
public <T> T getAttribute(String attributeName) {
T attributeValue = this.cached.getAttribute(attributeName);
if (attributeValue != null && RedisIndexedSessionRepository.this.saveMode.equals(SaveMode.ON_GET_ATTRIBUTE)) {
this.delta.put(RedisIndexedSSaveMode.ON_GET_ATTRIBUTEessionRepository.getSessionAttrNameKey(attributeName), attributeValue);
}
return attributeValue;
}
I've racked my brains for a long time for what is the function of SaveMode.ON_GET_ATTRIBUTE and asked many times to chatgpt, but it always gave me error answer and repeat error many time.
I also see the offical docment.
/**
* Same as {#link #ON_SET_ATTRIBUTE} with addition of saving attributes that have been
* read using {#link Session#getAttribute(String)}.
*/
ON_GET_ATTRIBUTE
and the Test
#Test
void saveWithSaveModeOnGetAttribute() {
given(this.redisOperations.<String, Object>boundHashOps(anyString())).willReturn(this.boundHashOperations);
given(this.redisOperations.boundSetOps(anyString())).willReturn(this.boundSetOperations);
given(this.redisOperations.boundValueOps(anyString())).willReturn(this.boundValueOperations);
this.redisRepository.setSaveMode(SaveMode.ON_GET_ATTRIBUTE);
MapSession delegate = new MapSession();
delegate.setAttribute("attribute1", "value1");
delegate.setAttribute("attribute2", "value2");
delegate.setAttribute("attribute3", "value3");
RedisSession session = this.redisRepository.new RedisSession(delegate, false);
session.getAttribute("attribute2");
session.setAttribute("attribute3", "value4");
this.redisRepository.save(session);
assertThat(getDelta()).hasSize(2);
}
I think the Test is just as I thought.It repeatly add attribute2=value2 to redis.I really unkown why the Test is writend like that.
please, who can tell me waht the function of SaveMode.ON_GET_ATTRIBUTE

How to write documentation for observable return which throws exceptions in RxJava

Not sure how to document throws declaration in Java doc style. Below example:
/**
* Get Facebook Friends
*
* #param facebookToken - Facebook Token
* #return list of {#link User}
* #throws SomeCheckedException <- this is normally the way, but not for Observable return type
*/
public Observable<List<User>> getFriends(String facebookToken) {
return get("/me/friends", facebookToken)
.flatMap(response -> {
FacebookResponse facebookResponse = response.readEntity(FacebookResponse.class);
if (null != facebookResponse.getError()) {
return Observable.error(parseException(facebookResponse.getError()));
} else if (null == facebookResponse.getData()) {
return Observable.error(new FacebookException("Empty data"));
}
return Observable.just(facebookResponse.getData());
});
}
The method is supposed to return Observable.error(), and I want to developer who is gonna call this method know about possibly exception do be handled in onErrorNextResume, etc.
Docs don't cover anything similar.
You are right, this method does not throw any errors, but it can potentially return an Observable emitting an error. In the company where I am currently working, we highly use reactive programming and for these cases, we drop the #throw line and we add this information to the #return:
#return an {#link Observable} containing the retrieved {#link User}s; yields a {#link FacebookException} in case of empty data.

Java 3.0 get distinct values from a column mongodb

I am really struggling here and have looked at other questions but just cant seem to get the answer I need.
What I am trying to do is pull through all the unique values of a column and then iterate through them and add them to an array. Ending up with the one column being stored in my array, but one of each value that exists not the multiple like there currently is.
Every time I try and do .distinct it asks me for the return class I have tried many different class but it just doesn't seem to work... Code is below any help would be appreciated.
public static void MediaInteraction() {
//Storing data from MediaInteraction in MediaArray
//BasicDBObject Query = new BasicDBObject();
//Query.put("consumerid", "");
MongoCursor<Document> cursormedia = collectionmedia.distinct("consumerid", (What do I put here?)).iterator();
while (cursormedia.hasNext()) {
System.out.println(cursormedia.next());
MediasessionID.add(cursormedia.next());
}
System.out.println("Media Array Complete");
System.out.println(MediasessionID.size());
}
The change that you probably want to introduce shall be somewhat like -
MongoCursor<Document> cursormedia = collectionmedia.distinct("consumerid",
<ConsumerId-DataType>.class).iterator(); //please replace the consumerId field's datatype here
Also from the docs -
/**
* Gets the distinct values of the specified field name.
*
* #param fieldName the field name
* #param resultClass the class to cast any distinct items into.
* #param <TResult> the target type of the iterable.
* #return an iterable of distinct values
* #mongodb.driver.manual reference/command/distinct/ Distinct
*/
<TResult> DistinctIterable<TResult> distinct(String fieldName, Class<TResult> resultClass);
So in your example, if you are trying to attain cursor for Document you probably want to use Document.class in the above suggested code.
Edit - Also the fact that you are calling cursormedia.next() twice the count of your MediasessionID would be halved. Suggest you do that(.next) once improving it further to obtain results.

Spring Specification With Sum Function

I am trying a sum function in spring specification as below:
#Override
public Predicate toPredicate(Root<Stock> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
Path expression = root.get("qty");
query.select(builder.sum(expression));
return null;
}
The query I want to execute is:
SELECT SUM(o.qty) FROM Stock o;
But Spring is not creating a sum function and is executing this:
SELECT o.qty FROM Stock o
I checked so many Stack Overflow question but there is no answer in Specification way, most of the people use JPQL for #Query annotation for this. But my further query and design is very complex so I have to use Specification only. Because I need fully dynamic query.
There is similar question as well, and this as well.
I think this is not possible out of the box.
Here is the reason why.
I'm referring to Spring JPA 1.7.3 (source code can be found here: http://grepcode.com/snapshot/repo1.maven.org/maven2/org.springframework.data/spring-data-jpa/1.7.3.RELEASE/)
A JPA specification is used via JPA repository, e.g.:
myRepo.findAll(mySpec);
The source code for this function is:
/*
* (non-Javadoc)
* #see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll(org.springframework.data.jpa.domain.Specification)
*/
public List<T> findAll(Specification<T> spec) {
return getQuery(spec, (Sort) null).getResultList();
}
Here is the first issue here: the return type and query type are bound to entity type T. In your case it means that return result is going to be a list of Stock entities.
Second issue is with the way select list is composed in getQuery() function:
/**
* Creates a {#link TypedQuery} for the given {#link Specification} and {#link Sort}.
*
* #param spec can be {#literal null}.
* #param sort can be {#literal null}.
* #return
*/
protected TypedQuery<T> getQuery(Specification<T> spec, Sort sort) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<T> query = builder.createQuery(getDomainClass());
Root<T> root = applySpecificationToCriteria(spec, query);
query.select(root);
if (sort != null) {
query.orderBy(toOrders(sort, root, builder));
}
return applyRepositoryMethodMetadata(em.createQuery(query));
}
As you can see this type of call explicitly selects root (which is of type T or Stock in your case) and since it's executed after applying specification to criteria query, it overrides whatever you do in specification.
There is a workaround, though.
You can extend an existing JPA repository class:
public class MyRepositoryImpl<T>
extends SimpleJpaRepository<T, Integer> implements MyRepository<T>
{
and add special methods with appropriate signatures to perform what you need:
public <P> P calcAggregate(EntitySpecification<T> spec, SingularAttribute<?,P> column)
{
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<P> query = criteriaBuilder.createQuery(column.getJavaType());
if (spec != null)
{
Root<T> root = query.from(getDomainClass());
query.where(spec.toPredicate(root, query, criteriaBuilder));
query.select(criteriaBuilder.sum(root.get(column.getName())));
}
TypedQuery<P> typedQuery = em.createQuery(query);
P result = typedQuery.getSingleResult();
return result;
}
Then use it as:
myRepo.calcAggregate(mySpec, Stock_.qty);
where Stock_ is a metamodel class for Stock entity.
This is a very simple example with just one field and without ability to select an aggregate operation. It can be extended to suit one's needs.

Check whether the document exists using Mongodb and Java?

I have created a simple java application as my college mini project in which one of the module I'm allowing users to perform operations like insert, delete, update and search.
For validation purposes I want a to display an error message to the user if he tries to delete a record which isn't present in the DB like
"Sorry record not found" .
I have tried try catch block to check that if mongodb throws a exception if document not found but that didn't worked. I'm new in Java and Mongodb and need help.
Here's my code of deleteActionPerformed and of what I tried:
private void deleteActionPerformed(java.awt.event.ActionEvent evt) {
try {
// my collection name is activity
DBCollection col = db.getCollection("activity");
// Tid is the TextField in which i am taking input of _id
if(!Tid.getText().equals("")) {
col.remove(new BasicDBObject().append("_id",(Object)Tid.getText()));
} else {
JOptionPane.showMessageDialog(null,"Please Enter the ID");
}
} catch(Exception e){
JOptionPane.showMessageDialog(null,"Record not Found " + e);
}
}
The try catch block is not generating a not found type exception.
This may not by the most efficient method, but it ought to work.
I adapted it from some code of mine looking for a particular document value (other than _id).
There may be a specialized method for _id.
/**
* Checks if an activity exists with a given id. if no such activity exists
* returns false. Returns true for one or more activities with a matching id.
*
* #param db
* #param id
* #return boolean - true if one or more functions with matching names exit.
*/
public static boolean activityExists(MongoDatabase db, ObjectId id) {
FindIterable<Document> iterable = db.getCollection("activity")
.find(new Document("_id", id));
return iterable.first() != null;
}
EDIT: It seems that it is best to use the count method. Please refer to the following answer:
How to check if document exists in collection using mongo Java driver 3.0+
In your case, it is significantly faster to use find() + limit() because findOne() will always read + return the document if it exists. find() just returns a cursor (or not) and only reads the data if you iterate through the cursor.
So instead of:
db.collection.findOne({_id: “myId”}, {_id: 1})
you should use:
db.collection.find({_id: “myId”}, {_id: 1}).limit(1)

Categories