MongoDB and Spring Data. Get size of array in entity - spring-data-mongodb

I have such entity.
#Document
public class Entity{
#Id
private String id;
private Set<Integer> ids;
}
I need to get size of array ids
How it can be done using Spring Data aggregation framework?
I'm trying something like this:
AggregationOperation match = Aggregation.match(where("id").is(id));
AggregationOperation group = Aggregation.group("ids");
Aggregation aggregation = Aggregation.newAggregation(match, group);
template.aggregate(aggregation, Entity.class, Entity.class);
Seems like I'm doing it totally wrong.

You can use like this;
Aggregation aggregation = newAggregation(match(criteria),group("ids").count().as("count"));
This will produce :
{"yourPOJO":[{"ids":[...],"count":5},...]}

Well you can use
Aggregation aggregation = newAggregation(match(criteria),group("ids").count().as("count"),unwind("ids"),group("ids._id").count().as("count1"));

I have found the solution!
Aggregation aggregation = Aggregation.newAggregation(Aggregation.match(match),
Aggregation.project("ids"), Aggregation.unwind("ids"), Aggregation.group().count().as("count"));
Now it works fine, without obtaining all items from array.
UPD: This one is better
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(where("id").is(id)),
Aggregation.project().and("ids").project("size").as("count"));

Related

Is there a way to avoid explicitly writing document fields as Strings in Spring Data MongoDB queries?

I have recently started to use Spring Data MongoDB and I wonder if there is any way to avoid writing entities' attributes explicitly as they are stored in the database. For example, given the following class representing a MongoDB collection:
public class Employee {
#Id
public String id;
private double salary;
...
}
If I want to make a query using MongoTemplate like:
public List findEmployeeBySalaryRange(double salary) {
Query query = new Query();
query.addCriteria(Criteria.where("salary").lt(salary));
...
}
I would like to avoid writing "salary", since that will make the code harder to maintain in the future in case the field name changes. I am thinking of something like getting the field name from the class attribute, but I am not quite sure how. Is there a way to do it? I have looked into the documentation but did not find anything related unless I missed it.
Thanks in advance.
You may create a Utility Class to store all database field names, use #Field annotation on field with constant from that class and use that constant in query to avoid error prone hardcoded Strings.
In Employee Model
#Field(DbFields.SALARY)
private double salary;
In Query,
query.addCriteria(Criteria.where(DbFields.SALARY).lt(salary));
In DbFields Utility class
public static final String SALARY = "salary";

How to get a document from mongodb by using its string id and string collection name in SpringData

I know that generally, we need to do something similar to this for getting a document back from mongodb in spring data:
Define a class and annotate it with #Document:
#Document ("persons")
public class Person
Use MongoTemplete:
mongoOps.findById(p.getId(), Person.class);
The problem is that in runtime I don't know the class type of the document, I just have its string collection name and its string Id. How is it possible to retrieve the document using SpringData? Something like this:
db.myCollectionName.findOne({_id: myId})
The result object type is not a concern, it can be even an object, I just want to map it to a jackson JsonNode.
A possible workaround for this you can use the aggregate function of mongooperation like this
AggregationResults<Object> aggResults = mongoOps.aggregate(newAggregation(match(Criteria.where("_id").is(myId)) ,
myCollectionName, Object.class);
return aggResults.getUniqueMappedResult();

Entity Framework Core using GroupBy() with Generic Repository Pattern

I want to use GroupBy() method dynamically with generic repository pattern.
In example my simple generic repository for count()
public Task<long> GetCountAsync(Expression<Func<IEntity, bool>> predicate, Func<IGrouping<object, TEntity>> groupBy)
{
IQueryable<TEntity> query = db.Set<TEntity>();
query = query.Where(predicate);
//how must i use group by method
//this give cast error
query = query.GroupBy(groupBy);
return await query.AsNoTracking().CountAsync();
}
How can i use GroupBy() method with entity framework core in generic repository pattern?

How do I query by nested Refs in objectify

I have this structure:
//////Entity to be filtered
public class StockItem{
#Index
private Ref<StockItemTypeEntity> stockItemType;
} `enter code here`
and
//////Ref
public class StockItemTypeEntity{
#Index
private Ref<StockItemProductTypeEntity> productType;
}
I want to filter StockItem like this:
stockItemQuery = stockItemQuery.filter("stockItemType.productType", fitlerWrapper.getProductType());
But this isn't working. How do I filter using nested Refs?
This is a join, which is not supported by the underlying datastore. That is to say, if you want to perform a join you have to do it yourself.
Depending on the shape of your data and what you are trying to do, one common solution is to denormalize the index data into the parent entity (index a 'productType' field in the StockItem). It does require keeping the data in sync.

Google app engine, objectify how to order by a sub entity field?

I have a Course entity that contains the following field
#Index
private #Load
Ref<Student> student;
The student entity then has the field
#Index
private String matric;
I want to load all the Course entities sorted using the students matric number.
I have tried using the "." operator to get the sub field like this
ofy().load().type(Course.class).filter("course", course).order("student.matric").list();
but this return no result.
Is it possible to do this? how?
I don't think that is possible with objectify. I would let Course implement Comparable:
#Entity
public class Course implements Comparable<Course> {
.
.
.
#Override
public int compareTo(Course otherCourse) {
return this.getStudent().getMatric().compareTo(otherCourse.getStudent().getMatric());
}
}
Remove the "order" part of the Objectify load and use Collections.sort() instead:
List<Course> courses = ofy().load().type(Course.class).filter("course", course).list();
Collections.sort(courses);
There are no joins in the datastore. If you want to query your Courses by Student properties, you probably will need to denormalize the data into the Course and index it. This means changing the Student data will also require changing Courses.
As an aside: This data model is weird. Are you sure what you're calling Course isn't really an Enrollment?

Resources