I have a collection with order headers and positions (as array) and I need an query which should give me:
quantity of customers
quantity of orders
summed up order value
all grouped by date and order type. I already got this covered by two queries (see below), but I want to have it in one.
The main problem to me is that I need to count the orders but with positions unwinded.
E.g.: Below would be a possible result of the combined query with the test data below:
/* 1 */
{
"_id" : {
"typ" : "WERBUNG",
"date" : "2017-07-08"
},
"orderQuantity" : 1.0,
"value" : 1000,
"customerQuantity" : 1
}
/* 2 */
{
"_id" : {
"typ" : "WERBUNG",
"date" : "2017-07-07"
},
"orderQuantity" : 2.0,
"value" : 100,
"customerQuantity" : 1
}
/* 3 */
{
"_id" : {
"typ" : "ANDERE",
"date" : "2017-07-08"
},
"orderQuantity" : 4.0,
"value" : 1500,
"customerQuantity" : 4
}
/* 4 */
{
"_id" : {
"typ" : "ANDERE",
"date" : "2017-07-07"
},
"orderQuantity" : 1.0,
"value" : 90,
"customerQuantity" : 1
}
... this would mean:
On 7-7 there where 3 orders (WERBUNG 2, ANDERE 1) for only 1 customer (WERBUNG 1, ANDERE 1 - will be counted twice here, bit this would be okay)
On 8-7 there where 5 orders (WERBUNG 1, ANDERE 4) for 5 customers (WERBUNG 4, ANDERE 1)
I have an idea that SortBy would help here, however we still use 3.2 - so no access to this stage (and some other usefull options as well...).
Cheers!
--
Some information which might help:
// Here are the sample orders:
/*1*/
{
"_id" : ObjectId("596075d5be8fc415341c7d43"),
"header" : {
"kundennummer" : "820130",
"auftragsdatum" : 0,
"bestellangaben" : "BLOCK1",
"information1" : "blocktest",
"erstellungsdatum" : 1499493785.25906,
"vorgabeauftragsnummer" : 87475000,
},
"ordertype" : "BLOCK1",
"customernnummer" : "820130",
"ordernumber" : 87475000,
"positions" : [
"artikelnummer" : 1985900,
"menge" : 1,
"bruttopreis" : 1000,
"_id" : ObjectId("596075d5be8fc415341c7d45")
}
],
"date" : "2017-07-08",
"type" : "WERBUNG"
}
/*2*/
{
"_id" : ObjectId("59608f64be8fc415341c7d46"),
"header" : {
"kundennummer" : "944867",
"auftragsdatum" : 0,
"bestellangaben" : "",
"information1" : "blocktest",
"erstellungsdatum" : 1499500356.10022,
"vorgabeauftragsnummer" : 87475001,
},
"ordertype" : "",
"customernnummer" : "944867",
"ordernumber" : 87475001,
"positions" : [
{
"artikelnummer" : 4029300,
"menge" : 1,
"bruttopreis" : 100,
"_id" : ObjectId("59608f64be8fc415341c7d5c")
}
],
"date" : "2017-07-08",
"type" : "ANDERE"
}
/*3*/
{
"_id" : ObjectId("5960925ebe8fc415341c7d5d"),
"header" : {
"kundennummer" : "981927",
"auftragsdatum" : 0,
"bestellangaben" : "",
"information1" : "blocktest",
"erstellungsdatum" : 1499501036.34265,
"vorgabeauftragsnummer" : 87475002,
},
"ordertype" : "",
"customernnummer" : "981927",
"ordernumber" : 87475002,
"positions" : [
},
"artikelnummer" : 4557300,
"menge" : 2,
"bruttopreis" : 100,
"_id" : ObjectId("5960925ebe8fc415341c7d74")
}
],
"date" : "2017-07-08",
"type" : "ANDERE"
}
/*4*/
{
"_id" : ObjectId("5960925ebe8fc415341c7d75"),
"header" : {
"kundennummer" : "981927",
"auftragsdatum" : 0,
"bestellangaben" : "BLOCK2",
"information1" : "blocktest",
"erstellungsdatum" : 1499414714,
"vorgabeauftragsnummer" : 87475003,
},
"ordertype" : "BLOCK2",
"customernnummer" : "981927",
"ordernumber" : 87475003,
"positions" : [
{ "artikelnummer" : 7081200,
"menge" : 3,
"bruttopreis" : 10,
"_id" : ObjectId("5960925ebe8fc415341c7d8f")
}
],
"date" : "2017-07-07",
"type" : "WERBUNG"
}
/*5*/
{
"_id" : ObjectId("596093ebbe8fc415341c7d90"),
"header" : {
"kundennummer" : "962422",
"auftragsdatum" : 0,
"bestellangaben" : "",
"information1" : "blocktest",
"erstellungsdatum" : 1499501507.75201,
"vorgabeauftragsnummer" : 87475004,
},
"ordertype" : "",
"customernnummer" : "962422",
"ordernumber" : 87475004,
"positions" : [
"artikelnummer" : 3545900,
"menge" : 4,
"bruttopreis" : 100,
"_id" : ObjectId("596093ebbe8fc415341c7d95")
}
],
"date" : "2017-07-08",
"type" : "ANDERE"
}
/*6*/
{
"_id" : ObjectId("596098e9be8fc415341c7ddf"),
"header" : {
"kundennummer" : "981927",
"auftragsdatum" : 0,
"bestellangaben" : "BLOCK3",
"information1" : "blocktest",
"erstellungsdatum" : 1499415886,
"vorgabeauftragsnummer" : 87475007,
},
"ordertype" : "BLOCK3",
"customernnummer" : "981927",
"ordernumber" : 87475007,
"positions" : [
{
"artikelnummer" : 1006199,
"menge" : 7,
"bruttopreis" : 10,
"_id" : ObjectId("596098e9be8fc415341c7de6")
}
],
"date" : "2017-07-07",
"type" : "WERBUNG"
}
/*7*/
{
"_id" : ObjectId("59609a47be8fc415341c7de7"),
"header" : {
"kundennummer" : "981225",
"auftragsdatum" : 0,
"bestellangaben" : "",
"information1" : "blocktest",
"erstellungsdatum" : 1499503113.21714,
},
"ordertype" : "",
"customernnummer" : "981225",
"ordernumber" : 87475008,
"positions" : [
{
"_id": ObjectId("59609a47be8fc415341c7e0d")
"artikelnummer" : 2308400,
"menge" : 8,
"bruttopreis" : 100,
}
],
"date" : "2017-07-08",
"type" : "ANDERE"
}
/*8*/
{
"_id" : ObjectId("59609a47be8fc415341c7e0e"),
"header" : {
"vorgabeauftragsnummer" : 87475009,
"erstellungsdatum" : 1499416697,
"information1" : "blocktest",
"bestellangaben" : "",
"auftragsdatum" : 0,
"kundennummer" : "981927",
},
"ordertype" : "",
"customernnummer" : "981927",
"ordernumber" : 87475009,
"positions" : [
"_id" : ObjectId("59609a47be8fc415341c7e57"),
"bruttopreis" : 10,
"menge" : 9,
"artikelnummer" : 8017000
}
],
"date" : "2017-07-07",
"type" : "ANDERE"
}
// Query 1: Quantity of customers and order value by order type (WERBUNG, ANDERE) and day
db.getCollection('orders').aggregate([
{$unwind:"$positions"},
{$project: {
"_id": 1,
customer: "$header.customernnummer",
date: {$}ToString: {format: "%d-%m-%Y", }: {"$add":[ new }(0), {"$multiply": [1000, "$header.erstellungsdate"]}]} }},
edate: "$header.erstellungsdate",
ordertype: "$header.ordertype",
type: {$cond: { if: {$ne: ["$header.ordertype" ,""]} , then: "WERBUNG", else: "ANDERE" }},
value: {$multiply: ["$positions.price","$positions.quantity"]},
}
},
{$group: {
_id: {type: "$type", tag: "$date",customer: "$customer" },
type: {$first: "$type"},
date: {$first: "$date"},
wert: {$sum: "$value" }
}
},
{$project:{
_id : 0,
customer: "$customer",
type: "$type",
date: "$date",
wert: "$wert"
}
}
,{$group: {
_id: {typ: "$type", date: "$date"}, customerQuantity:{$sum:1},
value: {$sum: "$wert"}
}
},
{$sort:{
typ: 1, date: -1
}
}
]}
// Query 2: Order quantity by type, date
...
{$project: {
block: {$cond: { if: {$ne: ["$auftragskopf.bestellangaben" ,""]} , then: "WERBUNG", else: "ANDERE" }},
datum: {$dateToString: {format: "%d-%m-%Y", date: {"$add":[ new Date(0), {"$multiply": [1000, "$auftragskopf.erstellungsdatum"]}]} }},
}
},
{$group:{
_id: {block: "$block", datum: "$datum"},
auftragsanzahl:{$sum:1},
}
},
I'm not sure about how your data looks like, but I understand from this line
type: {$cond: { if: {$ne: ["$header.ordertype" ,""]} , then: "WERBUNG", else: "ANDERE" }}
that if your $header.ordertype is WERBUNG then you want your order type to be WERBUNG otherwise its ANDERE. With that in mind here is my solution.
db.getCollection('orders').aggregate([
{
$project: {
"_id": 1,
header: 1,
positions: 1,
date: {
$dateToString: {
format: "%Y-%m-%d",
date: {
"$add": [new Date(0), {
"$multiply": [1000, "$header.date"]
}]
}
}
},
type: {
$cond: {
if: {
$eq: ["$header.ordertype", "WERBUNG"]
},
then: "WERBUNG",
else: "ANDERE"
}
}
}
},
{
$group: {
_id: {
type: "$type",
date: "$date"
},
werbungCount: {
$sum: {
$cond: [{
$eq: ['$type', 'WERBUNG']
}, 1, 0]
}
},
andereCount: {
$sum: {
$cond: [{
$eq: ['$type', 'ANDERE']
}, 1, 0]
}
},
customer: {
$first: "$header.customernnummer"
},
date: {
$first: "$date"
},
type: {
$first: "$type"
},
positions: {
$first: "$positions"
}
}
},
{
$unwind: "$positions"
},
{
$project: {
"_id": 1,
customer: "$customer",
date: 1,
ordertype: "$header.ordertype",
type: "$type",
value: {
$multiply: ["$positions.price", "$positions.quantity"]
},
price: "$positions.price",
quantity: "$positions.quantity",
orderQuantity: {
$cond: {
if: {
$eq: ["$type", "WERBUNG"]
},
then: "$werbungCount",
else: "$andereCount"
}
},
}
},
{
$group: {
_id: {
type: "$type",
tag: "$date",
customer: "$customer"
},
type: {
$first: "$type"
},
date: {
$first: "$date"
},
wert: {
$sum: "$value"
},
orderQuantity: {
$first: "$orderQuantity"
}
}
},
{
$group: {
_id: {
typ: "$type",
date: "$date"
},
orderQuantity: {
$first: "$orderQuantity"
},
value: {
$sum: "$wert"
}
}
},
{
$sort: {
typ: 1,
date: -1
}
}
])
I use the first $project to "normalize" the date. So an order placed at 1499415886: Friday, July 7, 2017 8:24:46 AM and 1499415990: Friday, July 7, 2017 8:26:30 AM will both be counted since they are on the same date (cause I could also tell from what you wrote that the time doesn't matter to you, only the date)
In the $group after the $project you just count the documents that have the "ordertype" WERBUNG and set them to the field werbungCount, otherwise if they are empty set them to the field andereCount. The pipeline after the $project and the $group is like you did it. I just corrected some mistakes and changed the name of the fields in some spots. Also added the orderQuantity field with a condition on the second $project.
Hope that works!
I'm using VB in ASP.NET and I've been looking at trying to serialize the below JSON from a WebService(webmethod). plz help the exact properties that i used.
{
"api_version" : 4 ,
"hotel_ids" : [97497],
"start_date" : "2013-07-01",
"end_date" : "2013-07-03",
"num_adults" : 2,
"num_rooms" : 1,
"currency" : "USD",
"user_country" : "US",
"device_type" : "d",
"query_key" : "6167a22d1f87d2028bf60a8e5e27afa7_191_1360299600000_2_2",
"lang" : "en_US",
"num_hotels" : 1,
"hotels" :
[
{
"hotel_id": 97497,
"room_types":
{
"Fenway Room":
{
"url": "http: //www.partner-site.com/hotel_commonwealth/fenway_room?start_date=2013-07-01&end_date=2013-07-05&num_adults=2",
"price": 178.50,
"fees": 80,
"fees_at_checkout": 0,
"taxes": 20,
"taxes_at_checkout": 0,
"final_price": 278.50,
"discounts":
[
{
"marketing_text": "10% off entire stay during July",
"is_percent": true,
"amount": 10,
"price": 20,
"fees": 0,
"fees_at_checkout": 0,
"taxes": 0,
"taxes_at_checkout": 0,
"final_price": 20
},
{
"marketing_text": "1% off web special",
"is_percent": true,
"amount": 1,
"price": 2,
"fees": 0,
"fees_at_checkout": 0,
"taxes": 0,
"taxes_at_checkout": 0,
"final_price": 2
},
{
"marketing_text": "Waive property fee",
"is_percent": false,
"amount": 25,
"price": 0,
"fees": 25,
"fees_at_checkout": 0,
"taxes": 0,
"taxes_at_checkout": 0,
"final_price": 25
}
],
"currency": "USD",
"num_rooms": 1,
"room_code": "SINGLE",
"room_amenities":
[
"BREAKFAST_AND_LUNCH_INCLUDED",
"ROOM_WITH_A_VIEW"
]
}
}
}
]
}
Use Code like this:
This is my entity class
Public Class Book
' autocomplete example needs "id", "value" and the "label" variables to be sent back.
' do not change or remove "id", "value" and the "label" variables
Public Property id() As String
Public Property label() As String
Public Property value() As String
Public Property Author() As String
Public Property Genre() As String
Public Property Price() As String
Public Property Publish_date() As String
Public Property Description() As String
End Class
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
' Query string 'term' is for autocomplete. By default, it sends the variable
' "term" with the search word to the backend page.
Dim searchText As String = context.Request.QueryString("term")
Dim books As Collection = New Collection
Dim ds As New DataSet()
ds.ReadXml(HttpContext.Current.Server.MapPath("jsonfile"))
Dim dv As DataView = ds.Tables(0).DefaultView
dv.RowFilter = [String].Format("title like '{0}*'", searchText.Replace("'", "''"))
Dim book As Book
For Each myDataRow As DataRowView In dv
book = New Book()
book.id = myDataRow("id").ToString()
book.value = myDataRow("title").ToString()
book.label = myDataRow("title").ToString()
book.Author = myDataRow("author").ToString()
book.Genre = myDataRow("genre").ToString()
book.Price = myDataRow("price").ToString()
book.Publish_date = myDataRow("publish_date").ToString()
book.Description = myDataRow("description").ToString()
books.Add(book)
Next
Dim serializer As JavaScriptSerializer = New JavaScriptSerializer
Dim jsonString As String = serializer.Serialize(books)
context.Response.Write(jsonString)
End Sub