findBy to search inside an array in MongoRepository - mongodb

I have a Mongo document which is like this :
db.user.find()
{
"_id" : ObjectId("560fa0c730a8e74bbd69c094"),
"name" : "abc",
"employee" : [{
"_id" : BinData(3,"v0m0V46pok94fVfwGkFVig=="),
"team" : "Dev Engineer",
}]
}
class User
{
String name;
String id;
}
class Employee
{
UUID id;
String team;
}
public interface EmployeeRepository extends MongoRepository<Employee, String>
{
#Query(value = "{ 'employee._id' : ?0 }")
Medication findByEmployeeId(UUID Id);
}
I want to find the employee by id and write a find method using the employee._id. Is there anyway to do this using MongoRepository, or should I return the entire array and loop through it? I tried the above method findByEmployeeId(UUID Id), but it does not work. I am not sure if the #Query annotation is necessary here. Please suggest!

Related

Spring data mongodb filter nested object id in collection of String

I would like to filter mongodb collection by multiple nested object's object Id in String with Mongodb aggregation match operation. However spring data mongodb does not converts the String value to object Id in the match operation.
I was able to filter documents by multiple document Ids (primary key, not the nested object's object Id) in String value without any issues as Spring data mongodb converts the String values to oid:
{ "_id" : { "$in" : [{ "$oid" : "61a31853d268434139e7fc11"}, { "$oid" : "61a31853d268434139e7fc12"}]}
What I wanted to achieve is as below :
db.getCollection('products').aggregate(
[
{ "$match" : { "$and" : [{ "type._id" : { "$in" : [
ObjectId("618b99a3b4c24465b074b246"),
ObjectId("60afc0920dab8b6d3ac26355")
] }}]}}
])
But I always get the following :
db.getCollection('products').aggregate(
[
{ "$match" : { "$and" : [{ "type._id" : { "$in" : [
[{ "$oid" : "618b99a3b4c24465b074b246"}, { "$oid" : "60afc0920dab8b6d3ac26355"}]
]}}]}}
])
Spring data mongodb generated 2 dimensional arrays for the OIDs in the $in json
My Mongodb entities:
#Document(collection = "products")
public class Product {
#Id
private String id;
#NotNull
private ProductType type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Type getType() {
return type;
}
public void setType(ProductType type) {
this.type = type;
}
}
#Document(collection = "product_types")
public class ProductType {
#Id
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
My java code to execute the aggregation:
List<String> typeIds = Arrays.asList("618b99a3b4c24465b074b246", "60ad10ffc723877d8a977149");
List<AggregationOperation> aggregateOperations = new ArrayList<>();
Criteria criteria = Criteria.where("type._id").in(typeIds.stream().map(t -> new ObjectId(t)).collect(Collectors.toList()));
aggregateOperations.add(Aggregation.match(criteria));
Aggregation aggregation = Aggregation.newAggregation(aggregateOperations);
mongoTemplate.aggregate(aggregation, "products", ProductListDTO.class);
The mongodb collection data is as below:
{
"_id" : ObjectId("61a31853d268434139e7fc11"),
"type" : {
"_id" : ObjectId("618b99a3b4c24465b074b246")
}
}
It works as expected. When you log your aggregation pipeline, it writes as {$oid: 'hex'} (Same thing for the date).
Internally driver searches as ObjectId(...) as expected:
//WHEN
Criteria criteria = Criteria.where("type._id")
.in(typeIds.stream().map(ObjectId::new).collect(Collectors.toList()))
.and("date").is(new Date(currDate));
//Searches:
Document{{$match=Document{{type._id=Document{{$in=[618b99a3b4c24465b074b246]}}, date=Tue Dec 14 01:53:09 CET 2021}}}}
//LOG:
{
"aggregate": "__collection__",
"pipeline": [
{
"$match": {
"type._id": {
"$in": [
{
"$oid": "618b99a3b4c24465b074b246"
}
]
},
"date": {
"$date": "2021-12-14T00:53:09.817Z"
}
}
}
]
}

Filtering on a Mongo DB capped Collection using Flux

I have defined my capped collection as below.
#Document("#{#environment.getProperty('customProperties.cappedCollection')}")
#Data
#NoArgsConstructor
#Builder
#AllArgsConstructor
public class ActiveRideCapped {
#Id
private String id;
private String riderId;
private GeoJsonPoint location;
}
I am re-creating this collection at application startup using below code.
#Autowired
MongoOperations mongoOperations;
#PostConstruct
public void createCappedCollection() {
mongoOperations.dropCollection(ActiveRideCapped.class);
mongoOperations.createCollection(ActiveRideCapped.class, CollectionOptions.empty().maxDocuments(20).size(50000).capped());
}
The collection in DB looks like below.
{
"_id" : ObjectId("6037656d2f88af2124ba0d8c"),
"riderId" : "1",
"location" : {
"type" : "Point",
"coordinates" : [
0.1223,
2.2145
]
},
},
{
"_id" : ObjectId("603765532f88af2124ba0d8b"),
"riderId" : "2",
"location" : {
"type" : "Point",
"coordinates" : [
0.5468,
2.7856
]
}
}
I have written a capped repository as below
public interface ActiveRideCappedRepository extends ReactiveMongoRepository<ActiveRideCapped, String> {
#Tailable
Flux<ActiveRideCapped> findActiveRideCappedBy();
}
and I have written below code to create a stream of filtered records.
#Override
public Flux<ActiveRideCapped> getRiderLocationStream(String riderId) {
return activeRideCappedRepository.findActiveRideCappedBy().filter(p -> p.getRiderId()!=riderId);
}
My requirement is, I should get filtered stream based on the riderId I am passing. So if I pass riderId=1 then I should get flux of all records where riderId!=1. But the filtering isn't working! I am getting all the records present in capped collection.
What am I doing wrong here?

Spring Boot and Mongo - how to query by nested property

I have the following problem - how to query by nested property with #Query?
My Product class (document in Mongo):
#Document(collection = "products")
public class Product {
#Id
private String id;
#DBRef
private ProductProperties properties;
How does it look in Mongo:
{
"_id" : ObjectId("5d5e78d20e8e3d0006079a84"),
"companyId" : "1234",
"properties" : {
"$ref" : "properties",
"$id" : ObjectId("5df8dd2331ea7b4a9384335b")
},
"calendar" : [
{
"startDate" : ISODate("2019-09-04T22:00:00.000Z"),
"endDate" : ISODate("2019-09-09T22:00:00.000Z")
}
],
"_class" : "org.abc.def"
}
ProductProperties class (document in Mongo):
#Document(collection = "product_properties")
public class ProductProperties {
#Id
private String id;
(...)
How does it look in Mongo:
{
"_id" : ObjectId("5df8dd2331ea7b4a9384335b"),
"brand" : "offer Brand_1",
"model" : "offer model_1",
"modelNumber" : "offer model number_1",
"size" : {
...
}
My Spring repository:
public interface ProductRepository extends MongoRepository<Product, String> {
#Query("{'properties.id': ?0 }")
List<Product> findByPropertiesId(String propertiesId);
I've tried also:
List<Product> findByProperties_id(String propertiesId)
or
#Query("{'properties.$id': ?0 }")
List<Product> findByPropertiesId(ObjectId propertiesId);
but WITHOUT success. DO you know what's wrong?
When I invoke:
public List<Product> findProductsByPropertiesId(String properties) {
if (properties == null) {
throw new IllegalArgumentException("onFind: propertiesId should not be null.");
}
return productRepository.findByProperties_Id(properties);
}
I get empty list:(
Maybe there is impossible to do that via Query?
#Query("{'properties.$id': ?0 }")
List<Product> findByPropertiesId(ObjectId propertiesId);
public List<Product> findProductsByPropertiesId(String properties) {
if (properties == null) {
throw new IllegalArgumentException("onFind: propertiesId should not be null.");
}
return productRepository.findByPropertiesId(new ObjectId(properties));
}

Spring Data - Query by List

Is it possible to make a List Query that results in one value? The following does not work. The result is null. The combination of optionValues will result in one variant.
Here is my Data:
OptionValues
[
{
"id" : "5cc248eeaa4a4f7b35454079",
"optionType" : {
"id" : "5cc2301ab2c4cea611ceb13d",
"name" : "size",
"title" : "Size"
},
"value" : "S"
}
]
Variant
{
"id" : "5cc24361b2c4cea611cee8c9,
"optionValues" : [
{
"id" : "5cc248eeaa4a4f7b35454079",
"optionType" : {
"id" : "5cc2301ab2c4cea611ceb13d",
"name" : "size",
"title" : "Size"
},
"value" : "S"
}
],
"price" : 10.99
}
Variant Model
#Data
#Document
public class Variant extends StoreEntity {
#Id
private String id;
#DBRef
private List<OptionValue> optionValues;
...
}
OptionValues Model
#Data
#Document
public class OptionValue {
#Id
private String id;
#DBRef
private OptionType optionType;
private String value;
}
OptionType Model
#Data
#Document
public class OptionValue {
#Id
private String id;
private String name;
private String title;
}
Variant Repository
Variant findByOptionValues(List<OptionValue> optionValues);
Variant findByOptionValuesIn(List optionValues);

How to fetch all embedded document from the Mongo multiple documents using Spring Data Mongo

I am using Spring Data Mongo and I've almost 10,000 documents in mongoDB. I am using Spring Boot + Spring Data Mongo example.
I've following documents and each document has some unique and common address:
{
"_id" : ObjectId("592c7029aafef820f432c5f3"),
"_class" : "lankydan.tutorial.mongodb.documents.Person",
"firstName" : "John",
"secondName" : "Doe",
"dateOfBirth" : ISODate("2017-05-29T20:02:01.636+01:00"),
"address" : {
"addressLineOne" : "19 Imaginary Road",
"addressLineTwo" : "Imaginary Place",
"city" : "Imaginary City",
"country" : "US"
},
"profession" : "Winner",
"salary" : 100,
"hobbies" : [
{
"name" : "Badminton"
},
{
"name" : "TV"
}
]
}
Since, address is embedded into the User collection. How to fetch all the unique address or all address? I want to write service for this.
Do I need to create indexing for this?
You have to make a POJO class named Address in which you have to define its fields as :
public class Address {
private String addressLineOne;
private String addressLineTwo;
private String city;
private String country;
// getters and setters
}
Then, you have to modify your User.java class :
public class User {
private String id;
// other fields
private Address address;
// other fields
}
Spring's jackson liberary will automatically bind these fields to your POJO.
Now, when you try to get the fields of your address, you will get this by using :
System.out.println(user.getAddress.getAddressLineOne);
System.out.println(user.getAddress.getCity);
This can be simply achieved in the latest version of Spring Boot Starter Parent 2.1.4.RELEASE as per Spring Data Mongo Docs
List<Object> object = mongoTemplate.query(User.class).distinct("address").all();
for (Object object2 : object) {
Address address = (address) object2;
System.out.println(address);
}