Mongo Aggregation of $where: function() using MongoTemplate in SpringBoot [duplicate] - spring

i'm trying to compare two string in mongoDB spring Data.
My Code:
#GET
#Path("/reqvolatility")
#Produces(MediaType.APPLICATION_JSON)
public long getReqVolatility() throws JsonParseException, JsonMappingException, IOException{
String query = "{},{_id:0,levelId:1,reqID:1,creationTime:1,lastModified:1}";
Query query1 = new BasicQuery(query);
query1.addCriteria(Criteria.where("creationTime").ne("lastModified"));
long reqvolatility = getMongoOperation().count(query1,RequirmentVO.class);
return reqvolatility;
}
In the above code "creationTime" & "lastModified" columns in mongoDB.I'm comparing those two fields, but its not giving correct count.
Is this correct? if it is wrong, How can i compare two fileds?

Standard query operations do not compare the values of one field against another. In order to do this, you need to employ the JavaScript evaluation server side which can actually compare the two field values:
Assuming both fields are ISODate instances
BasicQuery query = new BasicQuery(
new BasicDBObject("$where", "this.creationTime.getTime() != this.lastModified.getTime()")
);

Related

Spring Data elastic search with out entity fields

I'm using spring data elastic search, Now my document do not have any static fields, and it is accumulated data per qtr, I will be getting ~6GB/qtr (we call them as versions). Lets say we get 5GB of data in Jan 2021 with 140 columns, in the next version I may get 130 / 120 columns, which we do not know, The end user requirement is to get the information from the database and show it in a tabular format, and he can filter the data. In MongoDB we have BasicDBObject, do we have anything in springboot elasticsearch
I can provide, let say 4-5 columns which are common in every version record and apart from that, I need to retrieve the data without mentioning the column names in the pojo, and I need to use filters on them just like I can do in MongoDB
List<BaseClass> getMultiSearch(#RequestBody Map<String, Object>[] attributes) {
Query orQuery = new Query();
Criteria orCriteria = new Criteria();
List<Criteria> orExpression = new ArrayList<>();
for (Map<String, Object> accounts : attributes) {
Criteria expression = new Criteria();
accounts.forEach((key, value) -> expression.and(key).is(value));
orExpression.add(expression);
}
orQuery.addCriteria(orCriteria.orOperator(orExpression.toArray(new Criteria[orExpression.size()])));
return mongoOperations.find(orQuery, BaseClass.class);
}
You can define an entity class for example like this:
public class GenericEntity extends LinkedHashMap<String, Object> {
}
To have that returned in your calling site:
public SearchHits<GenericEntity> allGeneric() {
var criteria = Criteria.where("fieldname").is("value");
Query query = new CriteriaQuery(criteria);
return operations.search(query, GenericEntity.class, IndexCoordinates.of("indexname"));
}
But notice: when writing data into Elasticsearch, the mapping for new fields/properties in that index will be dynamically updated. And there is a limit as to how man entries a mapping can have (https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-settings-limit.html). So take care not to run into that limit.

how to convert HAC flexible query to DAO query

I'm using below flexible query in HMC and it's working fine.
The same query needs to convert the DAO layer and input is a data parameter.
Please any help on this?
SELECT * FROM {Product} WHERE {creationtime} >= TO_DATE('2020/02/19','YYYY/MM/DD')
The complete and definitive guide for the creation of Flexiqueries and corresponding DAO code.
Refer DefaultProductDao and create one for your requirement or you can extend it if you want to reuse any function. I hope by looking at the class, you'll have an understanding of how to write and execute the flexi query in the SAP Hybris.
Converting your query to DAO
Here, I would suggest avoiding using TO_DATE or any DB function to ensure that the query is not DB dependent. In your case, you can parse string date to Java Date object and pass it to the query something like below
String query = "SELECT * FROM {"+ ProductModel._TYPECODE +"} WHERE {"+ ProductModel.CREATIONTIME +"} >= ?"+ProductModel.CREATIONTIME;
final FlexibleSearchQuery searchQuery = new FlexibleSearchQuery(query);
final Map<String, Object> params = new HashMap<String, Object>();
params.put(ProductModel.CREATIONTIME, getDateObject("2020/02/19"));
searchQuery.addQueryParameters(params);
final SearchResult searchResult = getFlexibleSearchService().search(searchQuery);
return searchResult.getResult();
Method
private Date getDateObject(String date)
{
// logic to parse your string date (YYYY/MM/DD) to java Date object
return new Date(); //return your parsed date object here
}

Sorting a custom JPA query with pageable

So, I've already done this using the standard Spring Data JPA interface which extends PagingAndSortingRepository in order to achieve pagination and sorting for a REST API. The thing is, now I want to achieve the very same thing but now using just vanilla JPA and so far so good I managed to get my API to paginate but the sorting doesn't work at all. Every time I try to set the parameter (from a pageable object using pageable.getSort()) it ends with a query error (either if I just send a string as parameter like "name" or just send the sort object, it shows errors).
Here's some code:
My repo implementation:
#Override
public List<Project> findByAll(Pageable pageable) {
Query query = em.createQuery("SELECT project FROM Project project ORDER BY :sort");
query.setParameter("sort", pageable.getSort());
query.setMaxResults(pageable.getPageSize());
query.setFirstResult(pageable.getPageSize() * pageable.getPageNumber());
return query.getResultList();
}
My service:
#Override
public Page<Project> findAll(Pageable pageable) {
objects = Lists.newArrayList(repository.findByAll(pageable));
PageImpl<Project> pages= new PageImpl<Project>(objects, pageable, repository.count());
return pages;
}
To be clear, I'm filling the Pageable object via URI and from the console I can say it's actually getting the data, so I assume the problem is with the repo.
Edit: This is the error I get when I replace the setParameter("sort", ...) for a hardcoded string aka query.setParameter("sort", "name"):
java.lang.NumberFormatException: For input string: "name"
And I think this method should stand for strings as well. If I use query.setParameter("sort", pageable.getSort()), the error is the same.
The order by cannot be set as a query parameter. Also, the Pageable.getSort().toString() likely won't return a string suitable for use in an order by clause as it will result in a String that represents the Order as property: ORDER, note the colon.
Here are some modifications that will work, assuming Java 8...
String order = StringUtils.collectionToCommaDelimitedString(
StreamSupport.stream(sort.spliterator(), false)
.map(o -> o.getProperty() + " " + o.getDirection())
.collect(Collectors.toList()));
Query query = em.createQuery(
String.format("SELECT project FROM Project project ORDER BY %s", order));

Using spring jdbc template to query for list of parameters

New to Spring JDBC template but I'm wondering if I am able to pass a list of parameters and execute query once for each parameter in list. As I've seen many examples, the list of parameters being passed is for the execution of the query using all the parameters provided. Rather I am trying to execute query multiple times and for each time using new parameter in list.
For example:
Let's say I have a List of Ids - params (Strings)
List<String> params = new ArrayList<String>();
params.add("1234");
params.add("2345");
trying to do something like:
getJdbcTemplate().query(sql, params, new CustomResultSetExtractor());
which I know as per documentation is not allowed. I mean for one it has to be an array. I've seen simple examples where query is something like "select * from employee where id = ?" and they are passing new Object[]{"1234"} into method. And I'm trying to avoid the IN() condition. In my case each id will return multiple rows which is why I'm using ResultSetExtractor.
I know one option would be to iterate over list and include each id in list as a parameter, something like:
for(String id : params){
getJdbcTemplate().query(sql, new Object[]{id}, new CustomResultSetExtractor());
}
Just want to know if I can do this some other way. Sorry, I Should mention that I am trying to do a Select. Originally was hoping to return a List of custom objects for each resultset.
You do need to pass an array of params for the API, but you may also assume that your first param is an array. I believe this should work:
String sql = "select * from employee where id in (:ids)"; // or should there be '?'
getJdbcTemplate().query(sql, new Object[]{params}, new CustomResultSetExtractor());
Or you could explicitly specify, that the parameter is an array
getJdbcTemplate().query(sql, new Object[]{params}, new int[]{java.sql.Types.ARRAY}, new CustomResultSetExtractor());
You can use preparedStatement and do batch job:
eg. from http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html
public int[] batchUpdate(final List<Actor> actors) {
int[] updateCounts = jdbcTemplate.batchUpdate("update t_actor set first_name = ?, " +
"last_name = ? where id = ?",
new BatchPreparedStatementSetter() {
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setString(1, actors.get(i).getFirstName());
ps.setString(2, actors.get(i).getLastName());
ps.setLong(3, actors.get(i).getId().longValue());
}
public int getBatchSize() {
return actors.size();
}
});
return updateCounts;
}
I know you don't want to use the in clause, but I think its the best solution for your problem.
If you use a for in this way, I think it's not optimal.
for(String id : params){
getJdbcTemplate().query(sql, new Object[]{id}, new CustomResultSetExtractor());
}
I think it's a better solution to use the in clause. And then use a ResultSetExtractor to iterate over the result data. Your extractor can return a Map instead of a List, actually a Map of List.
Map<Integer, List<MyObject>>
Here there is a simple tutorial explaining its use
http://pure-essence.net/2011/03/16/how-to-execute-in-sql-in-spring-jdbctemplate/
I think this is the best solution:
public List<TestUser> findUserByIds(int[] ids) {
String[] s = new String[ids.length];
Arrays.fill(s, "?");
String sql = StringUtils.join(s, ',');
return jdbcTemplate.query(String.format("select * from users where id in (%s)", sql),
ArrayUtils.toObject(ids), new BeanPropertyRowMapper<>(TestUser.class));
}
this one maybe what you want. BeanPropertyRowMapper is just for example, it will be very slow when there's a lot of records. you should change it to another more efficient RowMapper.

How to filter records according to `timestamp` in Spring Data Hadoop?

I have a hbase table with a sample record as follows:
03af639717ae10eb743253433147e133 column=u:a, timestamp=1434300763147, value=apple
10f3d7f8fe8f25d5bdf52343a2601227 column=u:a, timestamp=1434300763148, value=mapple
20164b1aff21bc14e94623423a9d645d column=u:a, timestamp=1534300763142, value=papple
44d1cb38271362d20911a723410b2c67 column=u:a, timestamp=1634300763141, value=scapple
I am lost as I was trying to pull out the row values according to the timestamp. I am using spring data hadoop.
I was only able to fetch all the records using below code:
private static final byte[] CF_INFO = Bytes.toBytes("u");
private static final byte[] baseUrl = Bytes.toBytes("a");
List<Model> allNewsList
= hbaseTemplate.find(tableName, columnFamily, new RowMapper<News>()
{
#Override
public Model mapRow(Result result, int rowNum)
throws Exception
{
String dateString = TextUtils.getTimeStampInLong(result.toString());
String rowKey = Bytes.toString(result.getRow());
return new Model(
rowKey,
Bytes.toString(result.getValue(CF_INFO, col_a)
);
}
});
How can I apply filter such that I would be able to get records within timestamp [1434300763147,1534300763142].
Hopefully this would help someone someday.
final org.apache.hadoop.hbase.client.Scan scan = new Scan();
scan.setTimeRange(1434300763147,1534300763142);
final List<Model> yourObjects = hbaseTemplate.find(tableName, scan, mapper);
Also, worth a mention, the max value of the timerange is exclusive, so if you want records with that timestamp to be returned, make sure to increment the max value of timerange by 1.
The problem was solved using Scanner object from Hbase Client.

Resources