I'm trying to convert the following Mongo query for use with Spring data.
db.product.aggregate([
{$unwind: '$barcodes'},
{$project: {
_id: 0,
productId: '$_id',
productTitle: '$title',
productVariation: '$variation',
barcode: '$barcodes'
}}])
This is what I've been trying so far. It returns the aggregation, but with null values:
UnwindOperation unwindOperation = Aggregation.unwind("barcodes");
ProjectionOperation projectStage = Aggregation.project().and("productId").as("_id").and("productTitle")
.as("title")
.and("productVariation").as("variation")
.and("barcodeTitle").as("barcodes.title")
.and("barcodeValue").as("barcodes.value")
.and("barcodeType").as("barcodes.type")
.and("codeStandard").as("barcodes.codeStandard")
.and("quantity").as("barcodes.quantity")
.and("status").as("barcodes.status");
SortOperation sortOperation = Aggregation.sort(Sort.by(Sort.Direction.DESC, "title"));
Aggregation agg = Aggregation.newAggregation(unwindOperation, projectStage, sortOperation);
AggregationResults<BarcodeAggregateList> results = mongoTemplate.aggregate(agg, "product", BarcodeAggregateList.class);
What it is returning:
The class I am mapping to (has getters/setters):
public class BarcodeAggregateList {
private String productId;
private String productTitle;
private String productVariation;
private String barcodeTitle;
private String barcodeValue;
private String barcodeType;
private String codeStandard;
private int quantity;
private String status;
}
Product class that the data is coming from:
public class Product implements Serializable {
private static final long serialVersionUID = -998149317494604215L;
private String id;
private String title;
private String description;
private String SKU;
private double cost;
private double retailPrice;
private String status;
private LocalDate launchDate;
private LocalDate discontinueDate;
private String discontinueReason;
private String salesChannel;
private List<Barcode> barcodes;
private ProductVariation variation;
private List<Supplier> supplier;
private Product parentProduct;
private boolean updateChildren;
private Label label;
private int secondaryStockLevel;
private int primaryStockLevel;
private Date createdDate;
private Date modifiedDate;
private List<Dimension> dimensions;
private boolean isDeleted = false;
}
Barcode class
public class Barcode {
private String type;
private String title;
private String value;
private String status;
private String codeStandard;
private int quantity;
}
I appreciate any help with this or resources to help me better understand how to perform these types of conversions.
For anyone trying to solve similar issues, I've found the following resources somewhat helpful:
https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.query
https://xpadro.com/2016/04/data-aggregation-with-spring-data-mongodb-and-spring-boot.html
https://www.tutorialspoint.com/get-fields-from-multiple-sub-documents-that-match-a-condition-in-mongodb
BarcodeAggregateList class fields are null because there is a minor issue in ProjectionOperation's and() and as() methods. The correct syntax is
Aggregation.project().and(SOURCE_FIELD).as(TARGET_FIELD)
You have written and("productId").as("_id") , which is wrong
You need to write this as and("_id").as("productId") , because source field is _id
complete code:
UnwindOperation unwindOperation = Aggregation.unwind("barcodes");
ProjectionOperation projectStage = Aggregation.project()
.and("_id").as("productId")
.and("title").as("productTitle")
.and("variation").as("productVariation")
.and("barcodes.title").as("barcodeTitle")
.and("barcodes.value").as("barcodeValue")
.and("barcodes.type").as("barcodeType")
.and("barcodes.codeStandard").as("codeStandard")
.and("barcodes.quantity").as("quantity")
.and("barcodes.status").as("status");
SortOperation sortOperation = Aggregation.sort(Sort.by(Sort.Direction.DESC, "productTitle"));
Aggregation agg = Aggregation.newAggregation(unwindOperation, projectStage, sortOperation);
AggregationResults<BarcodeAggregateList> results = mongoTemplate.aggregate(agg, "product", BarcodeAggregateList.class);
Related
I need to get some specific data from rest to my model.
Data I get from rest :
[{"id":595,"name":"TransXChange20210805113332","prosystem_file_id":null,"dataset":16,"creator":113,"editor":113,"created":"2021-08-05T09:45:21.444949Z","edited":"2021-08-05T09:45:27.542152Z","update_from_url":false,"description":"Rozkłady jazdy komunikacji miejskiej ważne od 08.08.2021","file":"https://otwartedane.erzeszow.pl/media/resources/transxchange20210805113332.xml","link":null,"extension":"XML","data_type":"[]","file_name":"transxchange20210805113332.xml","chart_info":null,"map_info":null,"score":4,"public":true,"licence":"other-open","connection_dict":null,"selection_string":null,"db_type":"POSTGRESQL","type":"file","dbview_cache_minutes":1,"preview_base64":null,"gpkg_display_info":null,"archive_to_csv":false},{"id":538,"name":"TransXChange20210513082611","prosystem_file_id":null,"dataset":16,"creator":113,"editor":113,"created":"2021-05-13T06:28:50.233464Z","edited":"2021-07-28T08:52:06.695966Z","update_from_url":false,"description":"Rozkłady jazdy komunikacji miejskiej ważne od 15.05.2021","file":"https://otwartedane.erzeszow.pl/media/resources/transxchange20210513082611.xml","link":null,"extension":"XML","data_type":"[]","file_name":"transxchange20210513082611.xml","chart_info":null,"map_info":null,"score":4,"public":true,"licence":"other-open","connection_dict":null,"selection_string":null,"db_type":"POSTGRESQL","type":"file","dbview_cache_minutes":1,"preview_base64":null,"gpkg_display_info":null,"archive_to_csv":false},{"id":544,"name":"TransXChange20210526143716","prosystem_file_id":null,"dataset":16,"creator":113,"editor":113,"created":"2021-05-26T12:40:42.587492Z","edited":"2021-07-28T08:52:04.417450Z","update_from_url":false,"description":"Rozkłady jazdy komunikacji miejskiej ważne od 01.06.2021","file":"https://otwartedane.erzeszow.pl/media/resources/transxchange20210526143716.xml","link":null,"extension":"XML","data_type":"[]","file_name":"transxchange20210526143716.xml","chart_info":null,"map_info":null,"score":4,"public":true,"licence":"other-open","connection_dict":null,"selection_string":null,"db_type":"POSTGRESQL","type":"file","dbview_cache_minutes":1,"preview_base64":null,"gpkg_display_info":null,"archive_to_csv":false}]
i got it in single line
my code in java :
RestTemplateBuilder builder = new RestTemplateBuilder();
String soc = builder.build().getForObject("https://otwartedane.erzeszow.pl/v1/datasets/16/resources/", String.class);
assert soc != null;
System.out.println(soc);
And the problem is I need to put them into model
My model:
public class Resource {
private long id;
private String name;
private long prosystem_file_id;
private int dataset;
private int creator;
private int editor;
private LocalDateTime created;
private LocalDateTime edited;
private boolean update_from_url;
private String description;
private String file;
private String link;
private String extension;
private String data_type;
private String file_name;
private String chart_info;
private String map_info;
private int score;
private boolean isPublic;
private String licence;
private String connection_dict;
private String selection_string;
private String db_type;
private String type;
private int dbview_cache_minutes;
private String preview_base64;
private String gpkg_display_info;
private boolean archive_to_csv;
All getters and setters are generated.
How can I put them into model for example List?
The problem is I get data like [{resource},{resource},{resource}].
As it states from the RestTemplate documentation
you can call to the getForObject method passing as an argument the desired deserialization class.
Something like:
RestTemplateBuilder builder = new RestTemplateBuilder();
Resource soc = builder.build().getForObject("https://otwartedane.erzeszow.pl/v1/datasets/16/resources/", Resource.class);
assert soc != null;
System.out.println(soc);
I have found answer to my question.
I need to assign my call to array of model.
Resource[] soc =builder.build().getForObject( URL , Resource[].class );
I get a JSON-Object as an array form an external source which looks like this:
[13823108,"Text1","Text2",null,null,1585730520000,1585753742000,null,null,"COMPLETED",null]
The array will always have null values at those positions, which is why I would like to ignore those.
My Java object is suppose to look like this:
#JsonFormat(shape = JsonFormat.Shape.ARRAY)
public class MyJsonObject {
private final String id;
private final String textField1;
private final String textField2;
private final Date started;
private final Date updated;
private final String status;
#JsonCreator
public MyJsonObject(
#JsonProperty("id") final String id,
#JsonProperty("textField1") final String textField1,
#JsonProperty("textField2") final String textField2,
#JsonProperty("started") final Date started,
#JsonProperty("updated") final Date updated,
#JsonProperty("status") final String status) {
this.id = id;
this.textField1 = textField1;
this.textField2 = textField2;
this.started = started;
this.updated = updated;
this.status = status;
}
[...]
}
When I try to unmarshal the Json the null values are used, which courses the additional values to be ignored:
MyJsonObject{id='13105603', textField1='Text1', textField2='Text2', started=null, updated=null, status='1569348774000'}
Is there a way to tell the ObjectMapper to ignore null values of the array? Can I achieve this without writing a specific Deserializer?
I already tried #JsonInclude(JsonInclude.Include.NON_NULL) with no effect.
I started using Project Reactor recently and I can't work out how to work with nested streams. I want to update data of outer Mono with some data of inner Mono.
#GetMapping("/search")
public Mono<Github> combineGithubData() {
WebClient client = WebClient.create("https://api.github.com");
Mono<Github> data = client.get().uri(URI.create("https://api.github.com/users/autocorrectoff")).retrieve().bodyToMono(Github.class);
data = data.map(s -> {
client.get().uri(URI.create("https://api.github.com/users/Kukilej")).retrieve().bodyToMono(Github.class).map(m -> {
s.setXXX(m.getName());
return m;
});
return s;
});
return data;
}
The field XXX is always returned as null, although I have set it to a value from inner Mono. I'm pretty sure this would work in RxJs. How do I make this work with Project Reactor?
edit:
the code of the Github class
import lombok.*;
#Getter #Setter
#Builder
#ToString
#NoArgsConstructor
#AllArgsConstructor
public class Github {
private String login;
private int id;
private String node_id;
private String avatar_url;
private String gravatar_id;
private String url;
private String html_url;
private String followers_url;
private String following_url;
private String gists_url;
private String starred_url;
private String subscriptions_url;
private String organizations_url;
private String repos_url;
private String events_url;
private String received_events_url;
private String type;
private boolean site_admin;
private String name;
private String company;
private String blog;
private String location;
private String email;
private String hireable;
private String bio;
private int public_repos;
private int public_gists;
private int followers;
private int following;
private String created_at;
private String updated_at;
private String XXX;
}
Your inner stream is not getting subscribed to. Either us flatMap, or better yet, use zip:
data
.zipWith(client.get().uri(...).retrieve().bodyToMono(Github.class))
.map(tuple2 -> {
//update tuple2.getT1() with m.getName() and return the updated tuple
return tuple2.mapT1(tuple2.getT1().setXXX(tuple2.getT2().getName()));
})
.map(tuple2 -> tuple2.getT1() //updated s);
zipWith() subscribes to the inner stream.
I am learning spring boot. As a part of this learning, I am creating a invoicing application's backend using REST Webservices. Here is my JSON Request.
{
"invoice": {
"invoiceNumber":"KB123456",
"custId":"123",
"pricingId":"234",
"empId":"456",
"gstCode":"HSN1234",
"invoiceSubTotal":"1234.00",
"invoiceGst":"18%",
"invoiceGstAmount":"123.45",
"invoiceTotal":"1357.45",
"invoiceLineItems": [
{
"invoiceLineNo":"KB123456-1",
"invoiceLineDesc":"Des123",
"invoiceQty":"2",
"invoicePpu":"0.18",
"invoiceGstCode":"HSN1235",
"invoiceGstPercentage":"18%",
"invoiceLineAmount":"123",
"invoiceLineTaxAmount":"12",
"invoiceLineTotalAmount":"135"
},
{
"invoiceLineNo":"KB123456-2",
"invoiceLineDesc":"Des124",
"invoiceQty":"4",
"invoicePpu":"0.17",
"invoiceGstCode":"HSN1235",
"invoiceGstPercentage":"18%",
"invoiceLineAmount":"126",
"invoiceLineTaxAmount":"14",
"invoiceLineTotalAmount":"140"
}
]
}
}
invoiceLineItems can house up to 15 objects.
Here are my Entities Invoice and InvoiceLineItems
Invoice.Java
#Entity
public class Invoice {
#Id
#GeneratedValue
private long invoiceId;
private String invoiceNumber;
private long custId;
private long pricingId;
private long empId;
private String gstCode;
private String invoiceSubTotal;
private String invoiceGst;
private String invoiceGstAmount;
private String invoiceTotal;
#Transient
#OneToMany(mappedBy="invoice")
private List<InvoiceLineItems> invoiceLineItems;
}
InvoiceLineItems.Java
#Entity
public class InvoiceLineItems {
#Id
#GeneratedValue
private long invoiceLineId;
private String invoiceNumber;
private String invoiceLineNo;
private String invoiceLineDesc;
private String invoiceQty;
private String invoicePpu;
private String invoiceGstCode;
private String invoiceGstPercentage;
private String invoiceLineAmount;
private String invoiceLineTaxAmount;
private String invoiceLineTotalAmount;
#ManyToOne
private Invoice invoice;
}
Here is my REST Controller
#RestController
public class InvoiceResourceController {
#Autowired
InvoiceRepository invoiceRepository;
InvoiceLineRepository invoiceLineRepository;
#PostMapping("/invoice")
public ResponseEntity<Invoice> createInvoice(#RequestBody Invoice invoice) {
List<InvoiceLineItems> invoiceLineItemsList = invoice.getInvoiceLineItems();
Invoice savedInvoice = invoiceRepository.save(invoice);
/* for (int i = 0; i < invoiceLineItemsList.size(); i++) {
InvoiceLineItems invLn = new InvoiceLineItems();
invLn = invoiceLineItemsList.get(i);
invoiceLineRepository.save(invLn);
} */
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}")
.buildAndExpand(savedInvoice.getInvoiceNumber()).toUri();
return ResponseEntity.created(location).build();
}
}
Now, I have two tables Invoice and Invoice_Line_Items created by Spring Boot. I am able to persist the Invoice Entity to the Invoice table, but I'm struggling to get the InvoiceLineItems Array Object from request and persisting to Invoice_Line_Items table.
Any help will be appreciated.
Solved it.
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "invoiceNumber")
private List<InvoiceLineItems> invoiceLineItems;
I have three domain classes.. Catalog, DeviceInventory, DeviceInventoryInfo..
Catalog class consists of all the devices being used, DeviceInventory class gives brief information about the costs initiated with the device and DeviceInventoryInfo gives the detailed description about the device inventory.
Device Inventory refers a field named modelId from Catalog class. Catalog class has one to many relationship with DeviceInventory. Whereas DeviceInventoryInfo class refers deviceInventory class with device inventory id having one to one relation. So whenever I call the insert web service, it says grammaticalSQLException. And this is what I get in my Console
Hibernate: select inventoryr0_.device_inventory_id as device_i1_7_, inventoryr0_.device_model_id as device_m4_7_, inventoryr0_.hospital_id as hospital2_7_, inventoryr0_.manufacturer_id as manufact3_7_, inventoryr0_.physical_status as physical5_7_, inventoryr0_.device_status as device_s6_7_ from device_inventory_register inventoryr0_ where inventoryr0_.device_inventory_id=?
Hibernate: select catalog0_.device_model_id as device_m1_4_0_, catalog0_.baseline_cost as baseline2_4_0_, catalog0_.device_category_id as device_c3_4_0_, catalog0_.device_classification_id as device_c4_4_0_, catalog0_.device_description as device_d5_4_0_, catalog0_.device_code as device_c6_4_0_, catalog0_.device_name as device_n7_4_0_, catalog0_.device_type_id as device_18_4_0_, catalog0_.equivalent_model_name as equivale8_4_0_, catalog0_.hospital_id as hospital9_4_0_, catalog0_.life_expectancy as life_ex10_4_0_, catalog0_.manufacturer_id as manufac11_4_0_, catalog0_.meter_type as meter_t12_4_0_, catalog0_.device_model_num as device_13_4_0_, catalog0_.replacement_cost as replace14_4_0_, catalog0_.device_status as device_15_4_0_, catalog0_.device_subcategory_id as device_16_4_0_, catalog0_.support_status as support17_4_0_, catalog0_.useful_life as useful_19_4_0_, categoryma1_.device_category_id as device_c1_5_1_, categoryma1_.device_category_description as device_c2_5_1_, categoryma1_.device_category as device_c3_5_1_, categoryma1_.hospital_id as hospital4_5_1_, categoryma1_.status as status5_5_1_, devicetype2_.device_type_id as device_t1_11_2_, devicetype2_.device_type_description as device_t2_11_2_, devicetype2_.device_type as device_t3_11_2_, devicetype2_.hospital_id as hospital4_11_2_, subcategor3_.device_subcategory_id as device_s1_10_3_, subcategor3_.device_category_id as device_c2_10_3_, subcategor3_.hospital_id as hospital3_10_3_, subcategor3_.status as status4_10_3_, subcategor3_.device_subcategory_description as device_s5_10_3_, subcategor3_.device_subcategory as device_s6_10_3_ from device_catalog catalog0_ inner join device_category_master categoryma1_ on catalog0_.device_classification_id=categoryma1_.device_category_id inner join device_type_master devicetype2_ on catalog0_.device_type_id=devicetype2_.device_type_id inner join device_subcategory_master subcategor3_ on catalog0_.device_subcategory_id=subcategor3_.device_subcategory_id where catalog0_.device_model_id=?
Hibernate: select inventoryr0_.s.no as s1_8_2_, inventoryr0_.date_of_acceptance as date_of_2_8_2_, inventoryr0_.account as account3_8_2_, inventoryr0_.baseline_cost as baseline4_8_2_, inventoryr0_.cost_to_date as cost_to_5_8_2_, inventoryr0_.device_inventory_id as device_i6_8_2_, inventoryr0_.stored_on_device as stored_o7_8_2_, inventoryr0_.hippa_data_id as hippa_da8_8_2_, inventoryr0_.date_of_installation as date_of_9_8_2_, inventoryr0_.date_of_launch as date_of10_8_2_, inventoryr0_.life_expectancy as life_ex11_8_2_, inventoryr0_.network_aware as network12_8_2_, inventoryr0_.network_connected as network13_8_2_, inventoryr0_.original_cost as origina14_8_2_, inventoryr0_.priority_id as priorit15_8_2_, inventoryr0_.date_of_purchase as date_of16_8_2_, inventoryr0_.date_of_receipt as date_of17_8_2_, inventoryr0_.replacement_cost as replace18_8_2_, inventoryr0_.risk_id as risk_id19_8_2_, inventoryr0_.skill_id as skill_i20_8_2_, inventoryr0_.transmitted_by_device as transmi21_8_2_, inventoryr0_.useful_life as useful_22_8_2_, inventoryr1_.device_inventory_id as device_i1_7_0_, inventoryr1_.device_model_id as device_m4_7_0_, inventoryr1_.hospital_id as hospital2_7_0_, inventoryr1_.manufacturer_id as manufact3_7_0_, inventoryr1_.physical_status as physical5_7_0_, inventoryr1_.device_status as device_s6_7_0_, catalog2_.device_model_id as device_m1_4_1_, catalog2_.baseline_cost as baseline2_4_1_, catalog2_.device_category_id as device_c3_4_1_, catalog2_.device_classification_id as device_c4_4_1_, catalog2_.device_description as device_d5_4_1_, catalog2_.device_code as device_c6_4_1_, catalog2_.device_name as device_n7_4_1_, catalog2_.device_type_id as device_18_4_1_, catalog2_.equivalent_model_name as equivale8_4_1_, catalog2_.hospital_id as hospital9_4_1_, catalog2_.life_expectancy as life_ex10_4_1_, catalog2_.manufacturer_id as manufac11_4_1_, catalog2_.meter_type as meter_t12_4_1_, catalog2_.device_model_num as device_13_4_1_, catalog2_.replacement_cost as replace14_4_1_, catalog2_.device_status as device_15_4_1_, catalog2_.device_subcategory_id as device_16_4_1_, catalog2_.support_status as support17_4_1_, catalog2_.useful_life as useful_19_4_1_ from device_inventory_register_info inventoryr0_ inner join device_inventory_register inventoryr1_ on inventoryr0_.device_inventory_id=inventoryr1_.device_inventory_id left outer join device_catalog catalog2_ on inventoryr1_.device_model_id=catalog2_.device_model_id where inventoryr0_.device_inventory_id=?
#Entity
#Table(name="device_catalog")
public class Catalog {
private Integer modelId;
private Integer hospitalId;
private Integer manufacturerId;
private String deviceCode;
private String modelNumber;
private String deviceName;
private String description;
private String equiModelName;
private Integer classificationId;
private Integer typeId;
private Integer categoryId;
private Integer subCategoryId;
private String meterType;
private Integer baselineCost;
private Integer replacementCost;
private Integer usefulLife;
private Integer lifeExpectancy;
private String supportStatus;
public enum Status{Active, Inactive}
#JsonBackReference
private ManufacturerMaster master;
private ClassificationMaster classificationMaster;
private DeviceTypeMaster deviceTypeMaster;
private CategoryMaster categoryMaster;
private SubCategoryMaster subCategoryMaster;
private Status status;
#JsonManagedReference
private Set<InventoryRegister> inventoryRegisters;
#Entity
#Table(name="device_inventory_register_info")
public class InventoryRegisterInfo {
private Integer serialNum;
private Integer deviceInventoryId;
private String account;
private Integer originalCost;
private Integer replacementCost;
private Integer costToDate;
private Integer baselineCost;
private Date purchaseDate;
private Date receiptDate;
private Date acceptanceDate;
private Date installationDate;
private Integer usefulLife;
private Integer lifeExpectancy;
private Date launchDate;
private String networkAware;
private String networkConnected;
private String deviceStored;
private String transmittedByDevice;
private Integer skillId;
private Integer priorityId;
private Integer hippaId;
private Integer riskId;
private InventoryRegister inventoryRegister;
#Entity
#JsonAutoDetect
#Table(name="device_inventory_register")
public class InventoryRegister {
private Integer deviceInventoryId;
private Integer modelId;
private Integer manufacturerId;
private Integer hospitalId;
private String physicalStatus;
private Status status;
#JsonBackReference
private Catalog catalog;
private InventoryRegisterInfo inventoryRegisterInfo;
So How could I stop unnecessary joins and circular references?
Did you try set circular references to null for each Entity before insert into DB?