Spring Mongo: Repository do not return date in order - spring

I am trying to get objects from Mongodb in ascending (or descending) timestamp order.
This is how the document looks like:
{
_id: 5b01ffe3cd8b295aed16d5c0Wed
temperature: 23
timestamp: Dec 13 09:27:00 CET 2017
}
I am using Spring repository:
public interface TemperatureRepo extends MongoRepository<TemperatureObject, String> {
public List<TemperatureObject> findAllByOrderByTimestampDesc();
}
But somehow, Desc and Asc queries never work. I always get the result set in same order (which is not ordered at all)
The attribute temperature is saved as Date not as String
Is this a bug or am I missing something?

try this, it will solve your problem.
List<TemperatureObject> temperatureObjects = temperatureRepo.findAll(new Sort(Sort.Direction.DESC, "timestamp"));

Related

findByDate returning documents from previous day

I'm trying to fetch a list of objects by date, but the resulted list is always of the day before.
#GetMapping("date")
ResponseEntity findByDate(#RequestParam #DateTimeFormat(pattern = "yyyy-MM-dd") Date date) {
log.info("date is: "+date);
log.info("Delfaul time zone is: "+ TimeZone.getDefault());
return ResponseEntity.ok(consumptionService.findByDate(date));
}
the controller calls the service, which calls HourlyConsumptionRepo:
public interface HourlyConsumptionRepo extends MongoRepository<HourlyConsumption, ObjectId> {
List<HourlyConsumption> findByDate(Date date);
}
Postman results
Postman results
I think it might be an issue of timezones, but I can't figure out how to fix it.
MongoDB uses UTC times by default. See here: https://www.mongodb.com/docs/v3.2/tutorial/model-time-data/. So those results are "valid", I'm assuming you are UTC+2.

How to filter Range criteria using ElasticSearch Repository

I need to fetch Employees who joined between 2021-12-01 to 2021-12-31. I am using ElasticsearchRepository to fetch data from ElasticSearch index.
How can we fetch range criteria using repository.
public interface EmployeeRepository extends ElasticsearchRepository<Employee, String>,EmployeeRepositoryCustom {
List<Employee> findByJoinedDate(String joinedDate);
}
I have tried Between option like below: But it is returning no results
List<Employee> findByJoinedDateBetween(String fromJoinedDate, String toJoinedDate);
My Index configuration
#Document(indexName="employee", createIndex=true,type="_doc", shards = 4)
public class Employee {
#Field(type=FieldType.Text)
private String joinedDate;
Note: You seem to be using an outdated version of Spring Data Elasticsearch. The type parameter of the #Document
annotation was deprecated in 4.0 and removed in 4.1, as Elasticsearch itself does not support typed indices since
version 7.
To your question:
In order to be able to have a range query for dates in Elasticsearch the field in question must be of type date (the
Elasticsearch type). For your entity this would mean (I refer to the attributes from the current version 4.3):
#Nullable
#Field(type = FieldType.Date, pattern = "uuuu-MM-dd", format = {})
private LocalDate joinedDate;
This defines the joinedDate to have a date type and sets the string representation to the given pattern. The
empty format argument makes sure that the additional default values (DateFormat.date_optional_time and DateFormat. epoch_millis) are not set here. This results in the
following mapping in the index:
{
"properties": {
"joinedDate": {
"type": "date",
"format": "uuuu-MM-dd"
}
}
}
If you check the mapping in your index (GET localhost:9200/employee/_mapping) you will see that in your case the
joinedDate is of type text. You will either need to delete the index and have it recreated by your application or
create it with a new name and then, after the application has written the mapping, reindex the data from the old
index into the new one (https://www.elastic.co/guide/en/elasticsearch/reference/7.16/docs-reindex.html).
Once you have the index with the correct mapping in place, you can define the method in your repository like this:
List<Employee> findByJoinedDateBetween(LocalDate fromJoinedDate, LocalDate toJoinedDate);
and call it:
repository.findByJoinedDateBetween(LocalDate.of(2021, 1, 1), LocalDate.of(2021, 12, 31));

Neo4j 6 Spring boot 2.4 migrate driver session query

I am trying to migrate to neo4j 6. Whats the equivalent of this method in neo4j6?
The Result here contains: {ref=Employee.... etc, so the actual Java objects.
//org.neo4j.ogm.session.Session is autowired
#GetMapping("/companies/{companyId}/refs")
public Result getCompanyRefs(#PathVariable final String companyId)
{
String query = "MATCH (company:Company)-[ref]-(refObj) where company.id=\"" + companyId + "\" RETURN company,ref,refObj";
return this.session.query(query, Collections.emptyMap());
}
I tried with the new neo4j driver like so:
//org.neo4j.driver.Driver is autowired
#GetMapping("/persons/{personId}/refs")
public Result getPersonRefs(#PathVariable final String personId)
{
String query = "MATCH (person:Person)-[ref]-(refObj) where person.id=\"" + personId + "\" RETURN person,ref,refObj";
return this.driver.session().run(query, Collections.emptyMap());
}
but this gives a Result which is not convertable to my #Node (entity) classes. The previous version gave a Result which contained the actual java objects(mapped to classes).
the result here is:Record<{person: node<7>, ref: relationship<8>, refObj: node<0>}>
Basically the main thing is: i need the nodes mapped to java objects. But i need them via a cypher query, because i need to do some things on the (Result) Nodes before deleting the relationships between them.
so it turns out it does give back the things i need.
Result result = this.getPersonRefs(id);
result.list().forEach((entry) -> {
The problem was that for example neither entry.get("refObj").asObject(), nor asNode() actually gave back what i thought it was supposed to give back.
The Solution:
entry.get("refObj").asMap()
this gives back the actual properties of the object. Then you just need to convert it to MyClass.class with an ObjectMapper.

Spring Redis: Range query "greater than" on a field

I am using Redis to store some data and later query it and update it with latest information.
Considering an example:
I receive File data, which carries info on the file and the physical storage location of that file.
One shelf has multiple racks, and each rack can have multiple files.
Each file has a version field, and it gets updated (incremented) when an operation on file is performed.
How do I plan to store?
I need to query based on "shelfID + rack ID" -- To get all files.
I need to query based on "shelfID + rack ID + version > XX" -- To get all files with version more than specified.
Now, to get all files belonging to a shelf and rack, is achievable in Spring Data Redis.
I create a key of the combination of 2 ID's and later query based on this Key.
private <T> void save(String id, T entity) {
redisTemplate.opsForValue().set(id, entity);
}
But, how do I query for version field?
I had kept "version" field as #Indexed, but spring repository query does not work.
#RedisHash("shelves")
public class ShelfEntity {
#Indexed
#Id
private String id;
#Indexed
private String shelfId;
#Indexed
private String rackId;
#Indexed
private String fileId;
#Indexed
private Integer version;
private String fileName;
// and other updatable fields
}
Repository method:
List<ShefEntity> findAllByShelfIdAndRackIdAndVersionGreaterThan(String centerCd,
String floorCd, int version);
Above, gives error:
java.lang.IllegalArgumentException: GREATER_THAN (1): [IsGreaterThan,
GreaterThan]is not supported for redis query derivation
Q. How do I query based on Version Greater than?
Q. Is it even possible with Spring Data Redis?
Q. If possible, how should I model the data (into what data structure), in order to make such queries?
Q. If we don't use Spring, how to do this in Redis using redis-cli and data structure?
May be something like:
<key, key, value>
<shelfId+rackId, version, fileData>
I am not sure how to model this in Redis?
Update 2:
One shelf can have N racks.
One rack can have N files.
Each file object will have a version.
This version gets updated (o -> 1 -> 2....)
I want to store only the latest version of a file.
So, if we have 1 file object
shelfId - 1
rackId - 1
fileId - 1
version - 0
.... on update of version ... we should still have 1 file object.
version - 1
I tried keeping key as a MD5 hash of shelfId + rackId, in hash data structure.
But cannot query on version.
I also tried using a ZSet.
Saving it like this:
private void saveSet(List<ShelfEntity> shelfInfo) {
for (ShelfEntity item : shelfInfo) {
redisTemplate.opsForZSet()
.add(item.getId(), item, item.getVersion());
}
}
So, version becomes the score.
But the problem is we cannot update items of set.
So for one fileId, there are multiple version.
When I query, I get duplicates.
Get code:
Set<ShelfEntity> objects = (Set<ShelfEntity>) (Object) redisTemplate.opsForZSet()
.rangeByScore(generateMd5Hash("-", shelfId, rackId), startVersion,
Double.MAX_VALUE);
Now, this is an attempt to mimic version > XX
Create ZSET for each shelfId and rackId combination
Use two methods to save and update records in Redis
// this methods stores all shelf info in db
public void save(List<ShelfEntity> shelfInfo) {
for (ShelfEntity item : shelfInfo) {
redisTemplate.opsForZSet()
.add(item.getId(), clonedItem, item.getVersion());
}
}
Use update to remove old and insert new one, Redis does not support key update as it's a table so you need to remove the existing and add a new record
public void update(List<ShelfEntity> oldRecords, List<ShelfEntity> newRecords) {
if (oldRecords.size() != newRecords.size()){
throw new IlleagalArgumentException("old and new records must have same number of entries");
}
for (int i=0;i<oldRecords.size();i++) {
ShelfEntity oldItem = oldRecords.get(i);
ShelfEntity newItem = newRecords.get(i);
redisTemplate.opsForZSet().remove(oldItem.getId(), oldItem);
redisTemplate.opsForZSet()
.add(newItem.getId(), newItem, newItem.getVersion());
}
}
Read items from ZSET with score.
List<ShefEntity> findAllByShelfIdAndRackIdAndVersionGreaterThan(String shelfId,
String rackId, int version){
Set<TypedTuple<ShelfEntity>> objects = (Set<TypedTuple<ShelfEntity>>) redisTemplate.opsForZSet()
.rangeWithScores(generateMd5Hash("-", shelfId, rackId), new Double(version),
Double.MAX_VALUE);
List<ShelfEntity> shelfEntities = new ArrayList<>();
for (TypedTuple<ShelfEntity> entry: objects) {
shelfEntities.add(entry.getValue().setVersion( entry.getScore().intValue()));
}
return shelfEntities;
}

Sorting a DataGridView by DateTime

I have a website that is written in asp.net using C#. grdStatus is an instance of System.Windows.Forms.DataGridView. It displays 2 columns -- StatusDate and Status. StatusDate contains DateTime values. Status contains strings. The problem is that when the grid is sorted on StatusDate, it does not sort the values as DateTimes. Honestly, I'm not quite sure how it's sorting them. When I click on the Status Date column header, it sorts the dates like this:
Status Date
9/24/2014 10:01:06 AM
9/24/2014 10:00:58 AM
9/23/2014 7:27:23 PM
9/1/2015 4:48:35 PM
10/22/2014 12:15:38 PM
10/22/2014 12:15:29 PM
10/22/2014 12:12:52 PM
10/22/2014 12:12:27 PM
It's certainly not sorting them by DateTime, but it doesn't seem to be sorting them alphabetically, either. Here's the method that refreshes the grid. I added the two lines indicated by ---> in an attempt to force it to sort the rows by DateTime, but they seem to have no effect.
private void RefreshGrid()
{
IEnumerable<OrderService.OrderDetailStatus> statusItems = services.OrderSvc.GetStatusHistoryForOrderDetail(OrderDetailId);
IEnumerable<ViewModels.StatusHistoryGridViewModel> gridItems = AutoMapper.Mapper.Map<IEnumerable<ViewModels.StatusHistoryGridViewModel>>(statusItems);
grdStatus.AutoGenerateColumns = false;
grdStatus.DataSource = gridItems.ToDataTable<ViewModels.StatusHistoryGridViewModel>();
--->grdStatus.Columns[0].ValueType = typeof(DateTime);
--->grdStatus.Sort(grdStatus.Columns[0], ListSortDirection.Ascending);
}
Here's the view model that's being used as the data source for the grid. As you can see, CreatedDate (which is mapped to StatusDate) is a DateTime member.
namespace IVGOffice.ViewModels
{
public class StatusHistoryGridViewModel
{
public string StatusName { get; set; }
public DateTime CreatedDate { get; set; }
}
}
I've looked at some other posting related to this, but I haven't found anything that helps. Can anyone explain to me how to get this to sort correctly?
Part of the problem was that I was overlooking that fact that one of the dates had a different year from the others. After I noticed that, I was able to get the control to sort the column by the date; however, I still wasn't able to get it to sort by both date and time. I think this may be a bug in the DateGridView control. I replaced it with an UltraGrid control from Infragistics and that worked correctly.

Resources