PHP mongodb sum query - php

MongoDB can not get the total.
MYSQL :
select sum(play) as toplam from videos
MongoDB :
$group = $naytu->db->videos->group(array(), array("toplam" => 0), "function(obj, prev) {prev.toplam = prev.toplam + obj.play - 0;}");
results (print_r)
Array
(
[retval] => Array
(
[0] => Array
(
[toplam] => NAN
)
)
[count] => 78656
[keys] => 1
[ok] => 1
)
where is the problem ?

In PHP #Neils answer is:
$mongo->videos->aggregate([
['$group' => ['_id' => null, 'toplam' => ['$sum' => '$play']]]
]);

The group() function is kind of an old form of achieving results like this, it will also not work with sharded collections. Better to familiarize yourself with aggregate:
db.collection.aggregate([
{"$group": { "_id": null, "toplam": {"$sum": "$play"} }}
]);
Output for you driver will just be a cursor just like using find.
for PHP Syntax
For the record, your usage seems to be way off. Much as above you just translate the relative JSON to Dicts, and if that is still a problem then use a JSON parser to show you how. All the arguments are valid JSON, so I'm reminding myself to do this for all examples now, so people can easily dump into their own language.
db.collection.group({
"key": {},
"reduce": "function(curr, result) { result.total += curr.play; }",
"initial": { "total": 0 }
})
But still, don't use this anyway. Stick to aggregate, it's a useful tool to learn.
Of course in all cases, make sure that all your data being applied to a sum is actually a number, or things will blow up on you.

Maybe this can help
"function(obj, prev) {prev.toplam = new NumberInt(prev.toplam) + new NumberInt(obj.play);}"

Related

Looping through a Snowflake with PHP (Discord.php)

This is my first post, I do a lot of reading here, so hopefully I avoid embarrassing myself. I've done a lot of searching on the topic, with little results, given that I am new to PHP it doesn't help either, and documentation is sparse on the topic.
The Discord API for PHP is limited to certain pieces of data which you can request, what I am attempting to do is: fetch the members, check what roles they have, and if they have it, count them.
Currently with the API you can count all members within a guild, however you cannot count all members within a guild with a specific role. My end conclusion is to loop through the snowflake and handle the comparisons myself.
This code returns the snowflake (up to 1000) for a guild:
<?php
$json_options = [
"http" => [
"method" => "GET",
"header" => "Authorization: Bot TOKENREDACTED"
]
];
$json_context = stream_context_create($json_options);
$json_get = file_get_contents('https://discordapp.com/api/guilds/GUILDIDREDACTED/members?limit=1000', false, $json_context);
$json_decode = json_decode($json_get, true);
print_r($json_decode);
?>
And the snowflake I am trying to loop through looks like this:
Array
(
[0] => Array
(
[nick] => nickname
[user] => Array
(
[username] => username
[discriminator] => 7697
[id] => 123456789012345
[avatar] => 32ad726b873445fff9145e47144a9465
)
[roles] => Array
(
[0] => 123456789012345678
[1] => 123456789012345678
)
[mute] =>
[deaf] =>
[joined_at] => 2018-05-18T07:22:49.562000+00:00
)
[1] => Array (annnd repeat for the next member)
As you can see the snowflake is quite complicated in terms of arrays.
What I am trying to do here is loop through each array entry ([0],[1],[2] etc.) then to the roles. If the [user] has the role ID 123456789012345678 (for example) then add that member to a count to print, if there's no match then it'll simply ignore that and move onto the next one. But I'm not really sure where to start with this. Any help or direction is appreciated, thank you.
You can use array-filter and get only the element you need with in-array and then count them using simple count method. Consider the following:
$arr = array_filter($json_decode, function($e) {return in_array("123456789012345678", $e['roles']);});
echo count($arr);
If the your "RoleId" is dynamic you can do:
$myRole = "123456789012345678";
$arr = array_filter($json_decode, function($e) use ($myRole) {return in_array($myRole, $e['roles']);});
If you also want to display the username you can do:
foreach($arr as $e) {echo $e['user']['username'];}
This is probably really, really bad practice, especially for a first post. #wesley murch thank you very much for the direction, I got it now. Also, feel free to reply so I can mark you as the answer. Here is the working code which I would like to share with everyone, and a following explanation of what the code does:
<?php
$json_options = [
"http" => [
"method" => "GET",
"header" => "Authorization: Bot Your-Discord-Bot-Token-Here"
]
];
$json_context = stream_context_create($json_options);
$json_get = file_get_contents('https://discordapp.com/api/guilds/your-guild-id-here/members?limit=1000', false, $json_context);
print_r(substr_count ( $json_get ,'Role-Id-To-Look-For'));
?>
This code will query the API for the snowflake, it then converts that snowflake to a string, and counts the occurrences of which that role is contained in the snowflake. In this case, I have 12 people with this role, I can confirm that it successfully returned a value of 12. In this usage case it wasn't necessarily a matter of parsing the array, I was able to just check the snowflake as a string for the ID I was looking for. This usage case is limited in the fact that it won't necessarily return any details of the members which have the role, so I wouldn't say it completely covers every single usage case.

How to find all documents where the value of a field is null or empty

I'm trying to write a simple Mongo query to return all documents where the value of a field is null (or an empty array, I'm not sure what you call it).
Here is my query;
db.getCollection('contact').find({'poco.name.email':false})
Here is a screenshot of my collection using RoboMongo;
Ultimately, I need to transfer this to some PHP. So far I have this working;
$conditions = array_merge($conditions, [
'owner.$id' => $this->getId(),
'poco.name.familyName' => "Smith",
//not sure what goes here.. something like
//'poco.emails' => null,
]);
return Model_Mongo_Contact::getContacts($conditions, $sort, $fields, $limit, $skip);
That's probably going to be harder to answer without more access to the methods.. Or maybe not I am very new to Mongo it might be really obvious.
I'm not PHP expert but I'll be doing in mongo shell as:
db.collection.find({
$and: [
{"poco.email":{$exists: true}},
{"poco.email":{$ne: []}}
]})
Query above will list all documents where poco.name.email is not missing and is not empty.
The basic concept when looking for an "empty" array or even "non-existent" is to use a property of "dot notation" and search where the 0 index of the array does not exist. This can be achieved with using the $exists operator:
$conditions = array_merge($conditions, [
'owner.$id' => $this->getId(),
'poco.name.familyName' => "Smith",
'poco.emails.0' => array( '$exists' => FALSE )
]);
That condition is true when either there is no property at all, or if it is something other than an array ( therefore no "0" field property ) or indeed an "empty" array ( since there is no content at the first index ).
This works best when the field is actually "indexed". So if in your "normal" structure you have "sub-documents" inside the array element with say a consistent field named "address" which is indexed as "poco.emails.address", then you are best of pointing to that specific indexed property to see if it $exists or not:
$conditions = array_merge($conditions, [
'owner.$id' => $this->getId(),
'poco.name.familyName' => "Smith",
'poco.emails.0.address' => array( '$exists' => FALSE )
]);
But if the array consists purely of "values" only and no "sub-documents", then simply testing for the 0 index position of the array as initially demonstrated will be enough.

json_decode is rounding floats, how can I prevent it?

I have a rather big json file with coordinates in the following format
"[[3.2,1],[4.8,2]]"
which represents (3.2,1) and (4.8,2)
I'm using these coördinates to generate a D3 geographic map, but when php is modelling this information into a geoJSONobject I encounter the following error:
I need to transform the coordinates into a array for which I use json_decode. However:
json_decode("[[3.2,1],[4.8,2]]")
returns
Array
(
[0] => Array
(
[0] => 3
[1] => 1
)
[1] => Array
(
[0] => 4
[1] => 2
)
)
Where I lose the decimals. How can I prevent this?
Edit:
{"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": "[[[8.7, 11], [8.89, 12.13],[9.27, 12.13], [9.9, 12], [9.7, 10.8], [8.7, 11]]]"
},
"properties": {
"name": "04",
"count": "25"
}
}]
}
This is an example of the data I'm getting as output. (It is supposed to represent a map of rooms which are get a density color by its usage)
I am able to parse this using jQuery.parseJSON(data), but running the following D3 code generates the weirdest errors:
val(svgname).append("g")
.selectAll("path")
.data(geoJSONobject.features)
.enter().append("path")
.attr("d", path)
...
I think it's because of the quotes around the array of coordinates.
Edit (2) - actual solution
The solution I accepted was a workaround, but the true issue was localized php-settings. using:
echo json_encode($dataset, JSON_NUMERIC_CHECK);
in the php-file, all the issues were resolved. Though I'd update the question since it is still being looked at (if anyone would encouter the issue)
I had the same problem. I solved it using the followin regex
SOLUTION 1
$yourJsonVariable = preg_replace('/:\s*(\-?\d+(\.\d+)?([e|E][\-|\+]\d+)?)/', ': "$1"', $yourJsonVariable);
Convert it into array
$array = json_decode($yourJsonVariable, true);
Credits goes to this SO LINK
SOLUTION 2
You can set ini_set('precision',1);
SOLUTION 3
$decoded = json_decode($encoded, true, null, JSON_BIGINT_AS_STRING);
NOTE: The Last solution will work only for PHP > 5.4
You might want to take a look at this Blog
Just wrap the values in quotes: json_decode('[["3.2","1"],["4.8","2"]]');

mongodb & php - How to use nested level condition in find()

First of all, I am VERY new to Mongodb, so please bear with me. I have a mongodb collection that has data like below (in PHP array representation):
Array
(
[_id] => MongoId Object
(
[$id] => 8974439e66777114648b47dc
)
[mechFamily] => X07_B22
[mechName] => X07_B22_61
[mechType] => Original
[spans] => Array
(
[noOfSpans] => 5
[span] => Array
(
[0] => Array
(
[type] => solid
[clipShape] => rectangle
[id] => 2d8c1d2a6756323beca8e6e59823e3b
My requirement is that I need to pass condition to find() which will give me only those records where noOfSpansis 10.
I tried:
$myCollection->find(array("spans.noOfSpans" => 10));
But that does not return anything, I looked at the nest query sections in docs as well as SO, but the answers are pretty confusing. Can anyone tell me how to query this mongodb structure?
I'm not fluent in PHP's syntax, so I'm going to translate your document into mongo shell syntax and then propose a query. Let me know if I did it wrong and I will try to correct it.
{
"_id" : "8974439e66777114648b47dc",
"mechFamily" : "X07_B22",
"mechName" : "X07_B22_61",
"mechType" : "Original",
"spans" : {
"noOfSpans" : 5,
"span" : [
{
"type" : "solid",
"clipShape" : "rectangle",
"id" : "2d8c1d2a6756323beca8e6e59823e3b"
}
]
}
}
The query to match documents where spans.noOfSpans is 10 is
db.collection.find({ "spans.noOfSpans" : 10 })
which looks to be the same as your PHP query that you say isn't working. Is my document structure incorrect? What do you mean when you say the find isn't returning anything? It's returning a cursor with no results? How are you checking?

POSTing a multidimensional array from Python

I'm trying to POST an array to a RESTful PHP API. The idea is to allow (n>0) records, each containing a remote_id, a dimension_id and a metric.
Here's my client Python:
data = urllib.urlencode([
("remote_id", 1),
("dimension_id", 1),
("metric",metric1),
("remote_id", 1),
("dimension_id", 2),
("metric",metric2)
])
response = urllib2.urlopen(url=url, data=data)
And here's my serverside PHP
<?php
print_r($_POST);
?>
This returns, predictably:
Array
(
[remote_id] => 1
[dimension_id] => 2
[metric] => 16
)
It looks to me like I'm overwriting every instance of remote_id, dimension_id and metric with the final values, which is unsurprising since they're all keyed with identical names.
What's the proper way to do this? I can see a horrible method with unique keys (1_remote_id, 1_dimension_id, 1_metric + 2_remote_id, 2_dimension_id, 2_metric) but that doesn't scale very well.
I guess I'm after something like this PHP, but in Python:
<?php
$observations = array();
$observations[] = [
"remote_id" => "a1",
"metric_id" => "foo",
"metric" => 1
];
$observations[] = [
"remote_id" => "a1",
"metric_id" => "bar",
"metric" => 2
];
?>
Appreciate any tips!
Sam
Don't quote me on this (I haven't done any PHP in a LOOONG time), but this may just work:
data = urllib.urlencode([
("remote_id[]", 1),
("dimension_id[]", 1),
("metric[]",metric1),
("remote_id[]", 1),
("dimension_id[]", 2),
("metric[]",metric2)
])
I would give it a try anyway.

Categories