Order repeating entries by sum of one field with distinct of another - django

I looked around and couldn't find a good answer for this, and I'm completely new to Mongo so here is the thing if someone can help.
I have a collection in mongo which holds user related data, in this manner:
{user: 4, rate: 2, location: 1}
{user: 5, rate: 4, location: 1}
{user: 6, rate: 3, location: 1}
{user: 5, rate: 2, location: 1}
{user: 4, rate: 5, location: 1}
...
{user: x, rate: y, location: z}
Now I need a query that will return me all the users on certain location (here is 1 but can be anything) together with final sum of all the rates for that user, and all that ordered by that same sum of rates (hope this makes sense). So something like this :
{4: 7, 5: 6, 6: 3} -> {user: sum(rate)} - ordered by sum(rate)
Any ideas guys?
I will be doing this in mongoengine for Django so if anyone knows how to do this there cool, but if not I'll just do a raw query so any help is good.
Thanks a bunch!

The MongoDB feature you are looking for is the Aggregation Framework.
Here is an example query in the mongo shell:
db.collection.aggregate(
// Find matching documents (can take advantage of suitable index if present)
{ $match: {
location: 1
}},
// Add up rates by user
{ $group: {
_id: "$user",
rates: { $sum: "$rate" }
}},
// Order by total rates (ascending)
{ $sort: { rates: 1 }}
)
Sample results given your data in the question:
[
{
"_id" : 6,
"rates" : 3
},
{
"_id" : 5,
"rates" : 6
},
{
"_id" : 4,
"rates" : 7
}
]
As an optional step in the aggregation, you might want to use $project to rename the grouped _id field to user.

Related

CARBONE.IO Conditional display (ifEQ)

I'm using Carbone to generate PDF with variables.
I need to make a conditional display. If a product have a specific category I need to display an information.
I tried to make the condition with ifEQ, show and showBeggin // showEnd but it does'nt work.
// My JSON
const json = {
shopping : {
sales :[
{
product_name: "Apple",
product_price: 2,
product_category: "fruits",
comment: "",
},
{
product_name: "Coke",
product_price: 3,
product_category: "soda",
comment: "",
},
{
product_name: "Cucumber",
product_price: 1.5,
product_category: "vegetable",
comment: "",
},
{
product_name: "Vodka",
product_price: 15,
product_category: "Alcohol",
comment: "Dangerous for health, prohibited at least 18 years old",
},
]
}
}
What I made on my document :
State
{d.shopping.sales[i].product_name} {d.shopping.sales[i].product_category(“Alcohol”):showBeggin} Information {d.shopping.sales[i].comment}, {d.shopping.sales[i].product_price}, {d.shopping.sales[i].produt_name}{d.shopping.sales[i].product_category::showEnd}
{d.shopping.sales[i+1].product_name}
Thank's for help !
Your example got a couple of errors, some fixes to do:
it is missing the ifEQ just before the showBegin
if the ifEQ argument is a string, it must be wrap with single quotes
showBeggin should be written showBegin
the last showEnd should be preceded by only one colon.
Here is your template with all corrections:
State
{d.shopping.sales[i].product_name} {d.shopping.sales[i].product_category:ifEQ('Alcohol'):showBegin}
Information {d.shopping.sales[i].comment}, {d.shopping.sales[i].product_price}, {d.shopping.sales[i].produt_name}{d.shopping.sales[i].product_category:showEnd}
{d.shopping.sales[i+1].product_name}
The conditional block documentation has been improved a lot, to get more examples: https://carbone.io/documentation.html#conditioned-output
Have a great day!

In Jest what's the best way to loop through an array of inputs and expected outputs?

If I want to write a test for a calculator that adds things together. I might define my tests like this:
const tests = [
{
input: [1, 2],
expected: 3,
},
{
input: [2, 1],
expected: 3,
},
{
input: [3, 4],
expected: 7,
},
{
input: [2, 10],
expected: 12,
},
{
input: [2, 5],
expected: 7,
},
...
]
tests.forEach((t) => {
expect(add(t.input)).toEqual(t.expected)
})
The problem is, if one of those tests fails, the error just says:
Expected: "7"
Received: "10"
216 | tests.forEach((t) => {
> 217 | expect(add(t.input)).toEqual(t.expected)
| ^
218 | })
From this, I can't tell if it was 3+4 that was calculated wrong, or 2+5 that was calculated wrong.
The alternative is instead of an array, define each one as its own test. However, that requires a lot more code, and you need to copy paste the expect statement everywhere.
So what is the best way to test complicated computation functions where you need to pass in many different permutations of input to be sure it is working?
You can use jest's test.each to define them as separate test cases:
test.each(tests)('add %j', ({ input, expected }) => {
expect(add(input)).toEqual(expected)
})
but better yet you'd define the tests as following to take advantage of the printf formatting:
const tests = [
[[1,2], 3],
[[2,1],3],
[[3,4],7],
[[2,10],12],
[[2,5],7]
]
test.each(tests)('add(%j) should equal %d', (input, expected) => {
expect(add(input)).toEqual(expected)
})
working example

Django query sum values from related table

I have two tables:
Ticket Table
id paid_with_tax
1 5
2 6
3 7
TicketAdjustment Table
id ticket_id value_with_tax
1 1 2
2 1 1
3 1 2
4 1 3
5 2 5
The query I use:
use = 0
Ticket.objects.all().annotate(
paid_amount=Sum(
F('paid_with_tax') +
Coalesce(F('ticketadjustment__value_with_tax'), 0) * use
)
)
the query would return the following:
[
{id: 1, paid_amount: 7},
{id: 1, paid_amount: 6},
{id: 1, paid_amount: 7},
{id: 1, paid_amount: 8},
{id: 2, paid_amount: 11},
{id: 3, paid_amount: 7},
]
but the above is incorrect since the Ticket Table id=1 values are duplicated by the TicketAdjustment Table values.
how can i get the query to sum the TicketAdjustment Table values and return the following:
[
{id: 1, paid_amount: 13},
{id: 2, paid_amount: 11},
{id: 3, paid_amount: 7},
]
Here the solution for your problem :
Ticket.objects.all().annotate(
paid_amount=(F('paid_with_tax') +
Sum(Coalesce(F('ticketadjustment__value_with_tax'), 0))
)
).values_list('id', 'paid_amount')
values_list select the field you want in your result.
In your primary request there is a big problem.
Sum(F('paid_with_tax') + Coalesce(F('ticketadjustment__value_with_tax'), 0) * use)
This ligne miltiply value_with_tax with zero. So give you zero. It's like :
Sum(F('paid_with_tax'))
You want the sum of value_with_tax for each ticket, this is why I move Sum on it :
Sum(Coalesce(F('ticketadjustment__value_with_tax'), 0))
And after add the value of paid_with_tax
NB : I remove your variable use, because don't know is goal.

Couchbase View _count Reduce For Given Keys

I am trying to write a view in Couchbase using a reduce such as _count which will give me a count of the products at an address.
I have some documents in the database in the following format;
Document 1
{
id: 1,
address: {
street: 'W Churchill St'
city: 'Chicago',
state: 'IL',
},
product: 'Cable'
}
Document 2
{
id: 2,
address: {
street: 'W Churchill St'
city: 'Chicago',
state: 'IL',
},
product: 'Cable'
}
Document 3
{
id: 3,
address: {
street: 'W Churchill St'
city: 'Chicago',
state: 'IL',
},
product: 'Satellite'
}
Document 4
{
id: 4,
address: {
street: 'E Foster Rd'
city: 'New York',
state: 'NY',
},
product: 'Free To Air'
}
I already have a view which gives me all the products at an address which uses a composite key such as;
emit([doc.address.street, doc.address.city, doc.address.state], null)
Now this leads me on to the actual problem, I want to be able to get a count of products at a address or addresses.
I want to be able to see for an array of "keys"
['W Churchill St','Chicago','IL']
['E Foster Rd','New York','NY']
which products and a count of them. So i would expect to see in my results.
'Cable' : 2,
'Satellite': 1,
'Free To Air': 1
however if I specified only this "key",
['W Churchill St','Chicago','IL']
I would expect to see
'Cable' : 2,
'Satellite': 1
How to write my view to accommodate this?
The solution to this was to append my product to the key like so;
emit([doc.address.street, doc.address.city, doc.address.state, doc.product], null)
Then using;
?start_key=[street,city,state]&end_key=[street,city,state,{}]&group_level=4
Result:
{"rows":[
{"key":['W Churchill St','Chicago','IL','Cable'], "value":2},
{"key":['W Churchill St','Chicago','IL','Satellite'], "value":1}
]}
I would then need to repeat this query for each of the addresses and sum the results.

Group documents using substring of a field

I am working with MongoDB and I am enjoying a lot!
There is one query I am having problems to work with:
I have this set of data that represents an hierarchy (a tree, where 1 is the root, 1.1 and 1.2 are children of 1, and so on)
db.test.insert({id:1, hierarchy:"1"})
db.test.insert({id:2, hierarchy:"1.1"})
db.test.insert({id:3, hierarchy:"1.2"})
db.test.insert({id:4, hierarchy:"1.1.1"})
db.test.insert({id:5, hierarchy:"1.1.2"})
db.test.insert({id:6, hierarchy:"1.2.1"})
db.test.insert({id:7, hierarchy:"1.2.2"})
db.test.insert({id:8, hierarchy:"1.2.3"})
So if I make a query:
> db.test.find()
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4760"), "id" : 1, "hierarchy" : "1" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4761"), "id" : 2, "hierarchy" : "1.1" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4762"), "id" : 3, "hierarchy" : "1.2" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4763"), "id" : 4, "hierarchy" : "1.1.1" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4764"), "id" : 5, "hierarchy" : "1.1.2" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4765"), "id" : 6, "hierarchy" : "1.2.1" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4766"), "id" : 7, "hierarchy" : "1.2.2" }
{ "_id" : ObjectId("546a6095cafd2fa3ff8e4767"), "id" : 8, "hierarchy" : "1.2.3" }
the document with id 1 represents the CEO and I would like to gather information about the teams under the VPs (1.1 and 1.2).
I would like to have an output like this
{
id: null,
teams:
[
{
manager: 2,
hierarchy: "1.1",
subordinates: 2
},
{
manager: 3,
hierarchy: "1.2",
subordinates: 3
}
]
}
I am having problems to aggregate the documents in the right "slot".
I tried to use a regex to aggregate using the substring, and project before grouping and create a new field which would be "manager_hierarchy", so I could group using this field. But with none of these approaches I had any kind of success, so I am stuck now.
Is there anyway I could accomplish this task?
EDIT: sorry, I forgot to make one thing explicit:
This query is to get information about subordinate teams of an employee. I've used an example as the CEO, but if I was the employee 1.2.3 in the hierarchy, I would like to see the teams 1.2.3.1, 1.2.3.2, ..., 1.2.3.xx
There is also the possibility (rare, but possible) that someone has more than 9 subordinates, so making a "hardcoded" substring would not work, since
$substr:["$hierarchy",0,3]}
would work for 1.2 but not for 1.10
and
$substr:["$hierarchy",0,4]}
would work for 1.10, but not for 1.2
You can get your results using the below aggregate pipeline operations.
Sort the rows based on their hierarchy, so that the manager
comes on top.
Group together records that start with similar ancestors.(i.e 1.1
or 1.2,...). The manager record will be on top for each group
due to the above sort operation.
Take the count of each group, so the number of subordinates
will be count-1(the manager record).
Again group the records to get a single array.
The code:
db.test.aggregate([
{$match:{"id":{$gt:1}}},
{$sort:{"hierarchy":1}},
{$group:{"_id":{"grp":{$substr:["$hierarchy",0,3]}},
"manHeir":{$first:"$hierarchy"},
"count":{$sum:1},"manager":{$first:"$id"}}},
{$project:{"manager":1,
"hierarchy":"$manHeir",
"subordinates":{$subtract:["$count",1]},"_id":0}},
{$group:{"_id":null,"teams":{$push:"$$ROOT"}}},
{$project:{"_id":0,"teams":1}}
])