How do I group by on a dbref in MongoDB with Doctrine - php

I want to do an aggregation query where I can group by a dbref. This is what I've tried.
$aggregation = array(
array(
'$group' => array(
'_id' => '$foreign.$id',
'doc' => array(
'$last' => '$$ROOT'
)
)
),
array(
'$sort' => array(
'date' => -1
)
)
);
return $this->getDocumentManager()->getDocumentCollection('AppBundle:Collection')->aggregate($aggregation)->toArray();
But this attempt fails because you're not allowed to use the second $ sign in '$foreign.$id'. How can I do this query?

After a lot of searching I've found this Bug Ticket on the monogdb Jira which deals with basically this / an similar issue.
The last comment on this ticket offers an workaround to resolve the issue as an command line code. I've taken this solution and built it into an aggregation query which solved my problem.
$aggregation = array(
array(
'$addFields' => array(
'foreignId' => array(
'$arrayToObject' => array(
'$map' => array(
'input' => array(
'$objectToArray' => '$foreign'
),
'in' => array(
'k' => array(
'$cond' => array(
array(
'$eq' => array(
array(
'$substrCP' => array(
'$$this.k', 0, 1
)
),
array(
'$literal' => '$'
)
)
),
array(
'$substrCP' => array(
'$$this.k',1,['$strLenCP' => '$$this.k']
)
),
'$$this.k'
)
),
'v' => '$$this.v'
)
)
)
)
)
),
array(
'$group' => array(
'_id' => '$foreignId',
'doc' => array(
'$last' => '$$ROOT'
)
)
),
array(
'$sort' => array(
'date' => -1
)
)
);
$this->getDocumentManager()->getDocumentCollection('AppBundle:Collection')->aggregate($aggregation)->toArray();
This query gives me the correct and expected result.

Related

How to convert mongoDB query into PHP?

My query is working in mongodb and produce output Properly. But same query i tried to run using php then it gives following error
Array
(
[ok] => 0
[errmsg] => A pipeline stage specification object must contain exactly one field.
[code] => 16435
)
Following is my MongoDB Query
db.sample_coll.aggregate(
{
$unwind: {
path:"$KeyValues",
includeArrayIndex:"arrayIndex",
preserveNullAndEmptyArrays:true
}
},
{
$project: {
timestamp:{
"$add":["$EventTS",{"$multiply":[60000,"$arrayIndex"]}]
} ,
"InputVolt":"$KeyValues.InputVolt",
arrayIndex:1
}
},
{
$match: {
$and: [
{InputVolt: {$ne: null}}
]
}
}
);
The Above query is converted in php
$pipeline = array(
array('$unwind' =>
array( 'path' => '$KeyValues'),
array( 'includeArrayIndex' => 'arrayIndex' ),
array( 'preserveNullAndEmptyArrays' => 'true' )
),
array(
'$project' => array(
'timestamp' => array(
'$add' => array(
'$EventTS',
array('$multiply' => array( 60000, '$arrayIndex' ))
)
),
array( 'InputVolt' => array( '$KeyValues', 'InputVolt' ) ) ,
array('arrayIndex' => 1)
)
),
array(
'$match' => array(
'$and' => array(
array('InputVolt' => array('$ne' => null )),
)
)
)
);
$result = $collection->aggregate($pipeline);
Kindly help to resolve this issue.
Thanks in advance
Your pipeline in PHP:
$pipeline = array(
array('$unwind' => array(
'path' => '$KeyValues',
'includeArrayIndex' => 'arrayIndex',
'preserveNullAndEmptyArrays' => true
)),
array('$project' => array(
'timestamp' => array(
'$add' => array('$EventTS', array('$multiply' => array(60000, '$arrayIndex')))
),
'InputVolt' => '$KeyValues.InputVolt',
'arrayIndex' => 1
)),
array('$match' => array(
'InputVolt' => array('$ne' => null)
))
);

Elasticsearch range filter not working (No filter registered for)

I'm trying ta add a range filter to my search (only articles with workflow status <= 5 should appear) and getting errors
what's wrong with my range?
$searchParams = array(
'index' => $config->search->index,
'type' => 'xxxxxxxxxx',
'size' => 10,
'from' => ($page - 1) * 10,
'body' => array(
'query' => array(
'filtered' => array(
'query' => array(
'multi_match' => array(
'query' => $query,
'fields' => array('title^8', 'caption^5', 'teasertext^4', 'articletext^2') // ^x = Gewichtung des Felds
),
),
'filter' => array(
'bool' => array(
'must' => array(
'term' => array(
'deleted' => 0,
'visible' => 1
),
'range' => array(
'workflow_status' => array('lte' => '5')
)
)
)
)
)
)
),
'sort' => array('_score', '_id:desc')
here my mapping for status:
"workflow_status": {
"type": "integer",
"index": "not_analyzed"
}
What you have is not a valid Query DSL , must should take in an array.
The body should be something on these lines :
body =>
array(
'query' => array(
'filtered' => array(
'query' => array(
'multi_match' => array(
'query' => $query,
'fields' => array('title^8', 'caption^5', 'teasertext^4', 'articletext^2') // ^x = Gewichtung des Felds
),
),
'filter' => array(
'bool' => array(
'must' => array(
array(
'term' => array(
'deleted' => 0
)
),
array('term' => array(
'visible' => 1
)
),
array(
'range' => array(
'workflow_status' => array('lte' => '5')
)
)
)

eBay API Platform Notifications - I'm not receiving all the ones I want

I'm using the eBay API and am trying to receive the following notifications:
ItemSold
FixedPriceTransaction
EndOfAuction
However, the only notification I receive is 'FixedPriceTransaction'.
The code I'm using to 'set' what notifications I receive, looks like this:
$opts = array(
'ApplicationDeliveryPreferences' => array(
'ApplicationEnable' => 'Enable',
'ApplicationURL' => 'http://my.domain/ebay_notifications.php',
),
'UserDeliveryPreferenceArray' => array(
'NotificationEnable' => array(
'EventType' => 'ItemSold',
'EventEnable' => 'Enable'
),
'NotificationEnable' => array(
'EventType' => 'EndOfAuction',
'EventEnable' => 'Enable'
),
'NotificationEnable' => array(
'EventType' => 'FixedPriceTransaction',
'EventEnable' => 'Enable'
)
)
);
Any idea what I'm doing wrong?
Schoolboy error on my account.
The 'UserDeliveryPreferanceArray' array contains multiple arrays.
All of them have the same key title: 'NotificationEnable'
This means only the last one is used - the one containing the 'FixedPriceNotification' event.
To remedy this, make each 'notification event' part of an indexed array:
'NotificationEnable' => array(
1 => array(
'EventType' => 'ItemSold',
'EventEnable' => 'Enable'
),
2 => array(
'EventType' => 'EndOfAuction',
'EventEnable' => 'Enable'
),
3 => array(
'EventType' => 'FixedPriceTransaction',
'EventEnable' => 'Enable'
)
)
Happy days.
Ok, maybe i am wrong but the working code should be:
$opts = array(
'ApplicationDeliveryPreferences' => array(
'ApplicationEnable' => 'Enable',
'ApplicationURL' => 'http://my.domain/ebay_notifications.php',
),
'NotificationEnable' => array(
1 => array(
'EventType' => 'ItemSold',
'EventEnable' => 'Enable'
),
2 => array(
'EventType' => 'AskSellerQuestion',
'EventEnable' => 'Enable'
),
3 => array(
'EventType' => 'FixedPriceTransaction',
'EventEnable' => 'Enable'
)
)
);
And not as I thought:
$opts = array(
'ApplicationDeliveryPreferences' => array(
'ApplicationEnable' => 'Enable',
'ApplicationURL' => 'http://my.domain/ebay_notifications.php',
),
'UserDeliveryPreferenceArray' => array(
'NotificationEnable' => array(
1 => array(
'EventType' => 'ItemSold',
'EventEnable' => 'Enable'
),
2 => array(
'EventType' => 'EndOfAuction',
'EventEnable' => 'Enable'
),
3 => array(
'EventType' => 'FixedPriceTransaction',
'EventEnable' => 'Enable'
)
)
);
The first one seems to work well so far. The last one generates 37 errors.
Thank you anyways for your huge suggestion.

MongoDB aggregate with PHP - group by on date

I am using an aggregate in MongoDB with PHP. The code looks like:
$results = $c->aggregate(array(
array(
'$project' => array(
'day' => array('$dayOfYear' => '$executed')
),
),
array(
'$group' => array(
'_id' => array('day' => '$day'),
'count' => array('$sum' => 1)
),
),
array(
'$sort' => array(
'_id' => 1
),
),
array(
'$limit' => 30
)
));
The problem with this, is that $dayOfYear does not sort correctly, because it sorts 2 then 3 then 345, 346... I need it to be date ascending. So, basically instead of simply doing $dayOfYear I need something like $year-$month-$dayOfMonth.
Unfortunately this does not work. Any ideas?
Thanks.
You can project those parts out and then group on them to enable you to group on the whole date:
$results = $c->aggregate(array(
array(
'$project' => array(
'year' => array('$year' => '$executed' ),
'month' => array('$month' => '$executed' ),
'day' => array('$dayOfMonth' => '$executed')
),
),
array(
'$group' => array(
'_id' => array('year' => '$year', 'month' => '$month', 'day' => '$day'),
'count' => array('$sum' => 1)
),
),
array(
'$sort' => array(
'_id.year' => 1,
'_id.month' => 1,
'_id.day' => 1
),
),
array(
'$limit' => 30
)
));
Something like that should do the trick allowing you to sort on, as you stated: $year-$month-$dayOfMonth.
You shouldn't sort on the entire _id because you've set that up to contain an object (which can sort oddly), so change your $sort to this instead to specifically sort by day of year:
'$sort' => array(
'_id.day' => 1
),

Lithium framework multiple 'or' statements in a query (using mongoDB)

I have started work with lithium framework + mongoDB recently. I want to do a really simple query which contains multiple or statements.
I have articles in the DB with publish_up and publish_down fields. I want to fetch only those records/documents which pulbis_down field is highert than now OR null AND publish_up field lower than now OR null.
$items = $article::find('all', array(
'conditions' => array(
'$or' => array(
'$gt' => array('publish_down', $mongoDateNow),
'publish_down' => $mongDateNull
),
'$or' => array(
'$lt' => array('publish_up', $mongoDateNow),
'publish_up' => $mongDateNull
),
)
));
Of course this snippet is wrong hence the second or statement overwrites the first one (because the same array key).
I tried to wrap them into an individual array but gives error.
Any idea?
This query will fetch articles with (publish_down > now OR publish_down = null) AND (publish_up < now OR publish_up = null)
$items = Articles::find('all', array(
'conditions' => array(
'$or' => array(
array('publish_down' => array('$gt' => $mongoDateNow)),
array('publish_down' => null)
),
'$or' => array(
array('publish_up' => array('$lt' => $mongoDateNow)),
array('publish_up' => null)
),
)
));
I don't know about lithium but in PHP you can use multiple $OR as below
$items = $article::find('all', array(
'conditions' => array(
'$or' => array(
array(
'$gt' => array('publish_down', $mongoDateNow),
'publish_down' => $mongDateNull
),
array(
'$lt' => array('publish_up', $mongoDateNow),
'publish_up' => $mongDateNull
)
),
)
));
I think the correct answer is:
'$and' => array(
array(
'$or'=>array(
array('publish_up' => null),
array('publish_up' => array('$lt' => $mongoDateNow))
)
),
array(
'$or'=>array(
array('publish_down' => null),
array('publish_down' => array('$gt' => $mongoDateNow))
)
)
)

Categories