:param label => ('Person'); :param relationshipType =>
('HAS_EMAILED'); :param limit => ( 100); :param config =>
({concurrency: 8, direction: 'Outgoing', weightProperty: null,
defaultValue: 1, dampingFactor: 0.85, iterations: 25, writeProperty:
'pagerank'}); //then we calculate pagerank with one simple command
CALL algo.pageRank($label, $relationshipType, $config);
How turn this into a CALL gds.pagerank.stream(...)?
[I saw his on the Bruggen Blog][1]
[1]: https://blog.bruggen.com/2019/12/part-23-revisiting-hillary-clintons.html
My solutions:
:param label => ('Person'); :param relationshipType => ('HAS_EMAILED'); :param limit => ( 100); :param config => ({concurrency: 8, direction: 'Outgoing', weightProperty: null, defaultValue: 1, dampingFactor: 0.85, iterations: 25, writeProperty: 'pagerank'});
CALL gds.graph.create(
'myGraph332',
'Person', { HAS_EMAILED:{orientation:'UNDIRECTED'} })
Then
CALL gds.pageRank.stream('myGraph332')
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).alias AS alias, score
ORDER BY score DESC, alias ASC
Related
I try to get a relational table by QueryBuilder, it works fine til I try to use skip/offset and take/limit. I expect such return:
[
{
"id": 1, // order.id
"locations": [ ... ] array of locations with same order.id
},
{
"id": 2,
"locations": [ ... ]
},
{
"id": 3,
"locations": [ ... ]
}
]
order.entity.ts
#PrimaryGeneratedColumn({ name: 'id' })
public id!: number;
#OneToMany((type) => Location, (location) => location.order, {
onDelete: 'NO ACTION',
onUpdate: 'NO ACTION',
})
public locations: Location[];
locations.entity.ts
#PrimaryGeneratedColumn({ name: 'id' })
public id!: number;
#ManyToOne((type) => Order, (order) => order.locations, {
nullable: false,
onDelete: 'NO ACTION',
onUpdate: 'NO ACTION',
})
#JoinColumn({ name: 'order_id' })
public order: Order = null;
[Query A] I get the desired output with following code: (but without using skip/take, the output is at top of this question)
const orders = getRepository(Order)
.createQueryBuilder('order')
.where('order.customer_id = :customer', { customer: user.id })
.leftJoinAndSelect('order.locations', 'location', 'location.order_id = order.order_id')
.getMany(); // output count is 35, output count with limit/take of 10 would be 10
[Query B] If I add skip/offset and take/limit, it would look like this:
const orders = getRepository(Order)
.createQueryBuilder('order')
.where('order.customer_id = :customer', { customer: user.id })
.leftJoinAndSelect('order.locations', 'location', 'location.order_id = order.order_id')
.skip(0)
.limit(10)
.getMany(); // output count is 5
But here, the output is correct but the length/count is totally wrong. Query A finds 35 orders with always 2 locations. If I remove leftJoinAndSelect from Query A and add skip and take, then it will find 35 orders as well. But Query B, with a limit/take of 10, gives me a output count of 5. It halfs the output! If limit/take is equal 8, the output is a length of 4. It halfs the output! Obviously, getMany does some magic, so I found getRawMany, what doubles the output. Because to each order, there are 2 locations. That's also not what I need. And the structure of this output is also wrong (as you can see below). getManyRaw is okay, but not if I use it with skip/take, because the output would be obviously wrong, because I need all locations to each order. Group By doesn't help here, because then I would have only 1 location by each order.
The output of getRawMany is like
[
{
"order_id": 1,
"locations_id": 100
},
{
"order_id": 1,
"locations_id": 101
},
{
"id": 2,
"locations_id": 102
},
{
"id": 2,
"locations_id": 103
},
{
"id": 3,
"locations_id": 104
},
{
"id": 3,
"locations_id": 105
}
]
As I said, using skip/take here, would give me a wrong result. How can I reach my expected output?
I hope I got your question, basically what you want to achieve is skip and take parent orders regardless of how many child locations it has. Is this correct?
If my understanding is correct, you may use such approach:
const orders = getRepository(Order) // use await if it inside async function
.createQueryBuilder('order')
.addSelect('#row_number := ' +
'CASE WHEN #parent_id <> location.order_id ' +
'THEN #row_number + 1 ' +
'ELSE #row_number END AS rn, ' +
'#parent_id := location.order_id'
)
.where('order.customer_id = :customer', { customer: user.id })
.leftJoinAndSelect('order.locations', 'location', 'location.order_id = order.order_id')
.innerJoin('(SELECT #row_number := 0)', 'init_row', '1 = 1')
.innerJoin('(SELECT #parent_id := 0)', 'init_id', '1 = 1')
.orderBy('location.order_id')
.having('rn <= 10')
.getMany(); // now output should be 10 in case u want to skip use rn > 10 AND rn <= 20 condition
I am not sure that this is a valid question or not. I have started working on mongodb aggregation. I have to make a graph for the data on daily, weekly, monthly basis.
I am using "$dayOfMonth", "$week", "$month" to group by depending on the date provided. ex if from and to dates difference is less or equal to 6 I am grouping on daily basis using "$dayOfMonth",
If from and to dates difference is greater than 6 and less than 30 grouping is done of "$week" and if differece is greater than 30 then grouping is done on monthly basis "$month".
I am passing date in my "$match". Is it possible to push 0 as keys if the gouping is not present.
example - from_date = "01/01/2018" to_date = "30/6/2018"
so grouping will be done on month. and suppose if I dont have date for 3 and 4th & 5th month. I want to push 0 in the nested keys as the value.
output = [
{"_id": "01/01/2018", "counter":12},
{"_id": "01/02/2018", "counter": 15},
{"_id":"01/06/2018", counter: 10}
]
expected_output =
[
{"_id": "01/01/2018", "counter":12},
{"_id": "01/02/2018", "counter": 15},
{"_id":"01/03/2018", counter: 0},
{"_id":"01/04/2018", counter:0},
{"_id":"01/05/2018", counter: 0},
{"_id":"01/06/2018", counter: 10}
]
I am using Rails and Mongoid Gem.
Query That I am using
converted = Analytics::Conversion::PharmacyPrescription.collection.aggregate([
{ "$match" => {
"organisation_id" => org_id.to_s,
"date" => {
"$gte" => from_date,
"$lte" => to_date
},
"role_ids" => {"$in" => [role_id, "$role_ids"]}
}
},{
"$project" => {
"total_count" => 1,
"converted_count" => 1,
"not_converted_count" => 1,
"total_invoice_amount" => 1,
"user_id" => 1,
"facility_id" => 1,
"organisation_id" => 1,
"date" => 1,
}
},{
"$group" => {
"_id" => { "#{groupby}" => "$date" },
"total_count" => {"$sum" => "$total_count"},
"converted_count" => { "$sum" => "$converted_count" },
"not_converted_count" => { "$sum" => "$not_converted_count"},
}
}
]).to_a
The Aggregation Framework can only aggregate the documents you have. You are actually asking it to add groups for documents that do not exist, but it has no way to "know" which groups to add.
What I would do is run the query as you have it, and afterwards "spread" the date units according to the chosen granularity (in your example it will be 01/01/2018, 01/02/2018, 01/03/2018, 01/04/2018, 01/05/2018, 01/06/2018, and run a simple function which will add an entry for each missing unit.
I have two million documents in one collection in mongodb. I'm trying to optimize my query.
I have a query like this:
Question
.where(
topic: {'$in': ["stress", "pregnant", "smoking", "cancer", "warts"]},
_type: 'Question',
is_closed: true,
picked_up_by_id: {'$ne': nil},
is_anonymous: false,
is_deleted: false
)
.order_by(updated_at: :desc)
Question has subclasses, so I use _type in my query to specify the name (type) of the class.
I tried to index using hint like this:
Question
.where(
topic: {'$in': ["stress", "pregnant", "smoking", "cancer", "warts"]},
_type: 'Question',
is_closed: true,
picked_up_by_id: {'$ne': nil},
is_anonymous: false,
is_deleted: false
)
.order_by(updated_at: :desc)
.hint({
topic: 1,
_type: 1,
is_closed: 1,
picked_up_by_id: 1,
is_anonymous: 1,
is_deleted: 1,
updated_at: -1
})
but I still get timeout.
Suppose I have :items with a has_many association with :properties, then I can search for all items that have a property with name 'a_name' and value 'a_value' like this
q: { properties_name_eq: 'a_name', properties_value_eq: 'a_value' }
Now what if I want to search for all items that have a property with name 'a_name' and value 'a_value' and also a property with name 'another_name' and value 'another_value'?
The following doesn't work as it joins the properties table only once
q: {
g: {
'0' => { properties_name_eq: 'a_name', properties_value_eq: 'a_value' },
'1' => { properties_name_eq: 'another_name', properties_value_eq: 'another_value'}
}
}
The generated SQL looks something like this
SELECT DISTINCT "items".* FROM "items"
LEFT OUTER JOIN "properties" ON "properties"."item_id" = "items"."id"
INNER JOIN ((SELECT "items".* FROM "items")) AS sel_111 on sel_111.id
WHERE
(("properties"."name" = 'a_name' AND "properties"."value" = 'a_value') AND ("properties"."name" = 'another_name' AND "properties"."value" = 'another_value'))
EDIT:
To make it more clear what I am after, I'll paste a spec below.
Item.create name: 'ab', properties_attributes: [{ name: 'a', value: 'a1'}, {name: 'b', value: 'b1'}]
Item.create name: 'a', properties_attributes: [{ name: 'a', value: 'a1'}]
Item.create name: 'b', properties_attributes: [{name: 'b', value: 'b1'}]
Item.create name: 'ax', properties_attributes: [{ name: 'a', value: 'a1'}, {name: 'b', value: 'x'}]
Item.create name: 'bx', properties_attributes: [{ name: 'a', value: 'x'}, {name: 'b', value: 'b1'}]
Item.create name: 'other', properties_attributes: [{ name: 'other', value: '123'}]
get :index, q: { properties_name_eq: 'a', properties_value_eq: 'a1' }
names = JSON.parse(response.body).map{|u| u['name']}
expect(names).to match_array ['ab', 'a', 'ax'] # OK!
get :index,
q: {
m: 'or',
g: {
'0' => { properties_name_eq: 'a', properties_value_eq: 'a1' },
'1' => { properties_name_eq: 'b', properties_value_eq: 'b1'}
}
}
names = JSON.parse(response.body).map{|u| u['name']}
expect(names).to match_array ['ab'] #FAILS!
Just use Model.search(params[:q].try(:merge, m: 'or')), using your example:
q: {
m: 'or',
g: {
'0' => { properties_name_eq: 'a_name', properties_value_eq: 'a_value' },
'1' => { properties_name_eq: 'another_name', properties_value_eq: 'another_value'}
}
}
You can find more information here
You need an or at the where level of your query, because properties.name can't be equal 'a_name' and 'another_name' at the same time. A second alias for the table is not required.
You can solve this by using multiple queries.
For each name + value property, get all item IDs with this property
Intersect the resulting IDs for each property into item_ids
In the final query on :items, add the clause WHERE id IN (item_ids)
Here's a code example that does steps 1 & 2:
def property_item_ids(conditions)
conditions.inject([]) do |result, (key, condition)|
result.method(result.empty? ? '+' : '&').(Property.ransack(m: "and", g: condition).pluck(:item_id).to_a)
end
end
Get the item IDs that have all properties:
conditions = {
'0' => { properties_name_eq: 'a', properties_value_eq: 'a1' },
'1' => { properties_name_eq: 'b', properties_value_eq: 'b1'}
}
item_ids = property_item_ids(conditions)
For step 3, invoke ransack with item_ids:
q: {
m: 'and',
g: {
'0' => { item_id_in: item_ids }
}
}
I have an Element model that belongs to User. I am trying to calculate the following hash: how many users have element count of 1, 2, 3, etc. The approach I take is to first generate a hash of {user -> num elements}, then I sort-of invert it using a second map-reduce.
Here's what I have so far:
Element.map_reduce(%Q{
emit(this.user_id, 1);
}, %Q{
function(key, values) {
return Array.sum(values);
}
}).out(inline: true).map_reduce(%Q{
if (this.value > 1) {
emit(this.value, this._id);
}
}, %Q{
function(element_count, user_ids) {
return user_ids.length;
}
}).out(inline: true)
This gives me an "undefined method `map_reduce'" error. I couldn't find the answer in the docs. Any help would be great.
I calculated the hash using aggregate instead mapreduce, first grouping by user, and then grouping again by elements count:
Element.collection.aggregate([
{
"$group" => {
"_id" => "$user_id", "elements_count" => {"$sum" => 1}
}
},
{
"$group" => {
"_id" => "$elements_count", "users_count" => {"$sum" => 1}
}
},
{ "$project" => {
"_id" => 0,
"users_count" => '$users',
"elements_count" => '$_id',
}
}
])
This returns the following array:
[
{"users_count"=>3, "elements_count"=>2},
{"users_count"=>4, "elements_count"=>3},
...
]
If needed it can also be sorted using $sort operator