I have a Test database with a collection called collection:
{
"_id": "576008e5b47a6120c800418d",
"UserID": "Paul",
"Page": "A"
}
I want to record webactivity and use mapreduce to get an outcome like
{
"_id": "Paul",
"value": {
"A": 1,
"B": 0,
"C": 0,
"D": 0,
"E": 0
}
}
For a start I tried a simple code with PHP 7 MongoDB Driver 1.1.7 MapReduce using command which failed to decode document from the server:
<?php
$manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");
$command = new MongoDB\Driver\Command(array(
"mapReduce" => "collection",
"map" => "function() { emit(this.UserID, 1); }",
"reduce" => "function(Users, Pages){".
"return Pages;}",
"out" => "ex"
));
try {
$cursor = $manager->executeCommand('Test.collection', $command);
$response = $cursor->toArray()[0];
} catch(MongoDB\Driver\Exception $e) {
echo $e->getMessage(), "\n";
exit;
}
var_dump($response);
?>
Any ideas will be appreciated thanks.
Not too sure if I would recommend MapReduce for this type of operation, would say the aggregation framework will do the aggregation with better performance since the operations are all done in native code without spawning the code to JavaScript for compiling (in the MapReduce case).
With the aggregation operation, all you would need is a $group pipeline that makes use of the $cond operator which allows you to tranform a logical condition into a value. In this case you'd want to specify the pages as keys and their count as the value, with the documents grouped by the UserID.
Consider running the following aggregation operation in mongo shell:
db.collection.aggregate([
{
"$group": {
"_id": "$UserID",
"A": {
"$sum": {
"$cond": [
{ "$eq": [ "$Page", "A" ] },
1,
0
]
}
},
"B": {
"$sum": {
"$cond": [
{ "$eq": [ "$Page", "B" ] },
1,
0
]
}
},
"C": {
"$sum": {
"$cond": [
{ "$eq": [ "$Page", "C" ] },
1,
0
]
}
},
"D": {
"$sum": {
"$cond": [
{ "$eq": [ "$Page", "D" ] },
1,
0
]
}
},
"E": {
"$sum": {
"$cond": [
{ "$eq": [ "$Page", "E" ] },
1,
0
]
}
}
}
}
])
which will produce the output:
{
"_id": "Paul",
"A": 1,
"B": 0,
"C": 0,
"D": 0,
"E": 0
}
for the above sample document.
For brevity, if suppose you have a list of the pages beforehand, you can dynamically produce the pipeline as follows:
var groupOperation = { "$group": { "_id": "$UserID" } },
pages = ["A", "B", "C", "D", "E"];
pages.forEach(function (page){
groupOperation["$group"][page] = {
"$sum": {
"$cond": [
{ "$eq": [ "$Page", page ] },
1,
0
]
}
};
})
db.collection.aggregate([groupOperation]);
Now, translating this to PHP follows:
<?php
$group_pipeline = [
'$group' => [
'_id' => '$UserID',
'A' => [
'$sum' => [
'$cond' => [ [ '$eq' => [ '$Page', 'A' ] ], 1, 0 ]
]
],
'B' => [
'$sum' => [
'$cond' => [ [ '$eq' => [ '$Page', 'B' ] ], 1, 0 ]
]
],
'C' => [
'$sum' => [
'$cond' => [ [ '$eq' => [ '$Page', 'C' ] ], 1, 0 ]
]
],
'D' => [
'$sum' => [
'$cond' => [ [ '$eq' => [ '$Page', 'D' ] ], 1, 0 ]
]
],
'E' => [
'$sum' => [
'$cond' => [ [ '$eq' => [ '$Page', 'E' ] ], 1, 0 ]
]
]
],
];
$aggregation = $collection->aggregate([ group_pipeline ]);
?>
Should you rather stick to MapReduce, then consider changing the map and reduce functions to :
db.collection.mapReduce(
function() {
var obj = {};
["A", "B", "C", "D", "E"].forEach(function (page){ obj[page] = 0; } );
obj[this.Page] = 1;
emit(this.UserID, obj);
},
function(key, values) {
var obj = {};
values.forEach(function(value) {
Object.keys(value).forEach(function(key) {
if (!obj.hasOwnProperty(key)){
obj[key] = 0;
}
obj[key]++;
});
});
return obj;
},
{ "out": { "inline": 1 } }
)
Which gives the output:
{
"results" : [
{
"_id" : "Paul",
"value" : {
"A" : 1,
"B" : 0,
"C" : 0,
"D" : 0,
"E" : 0
}
}
]
}
Translating the above mapReduce operation to PHP is trivial.
How to get the polygon coordinates of a specific property. It's very a huge file so the time to parse the file is a factor.
Is there a library to do that?
Sample of the geojson:
{
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::37001" } },
"features": [
{ "type": "Feature", "properties": { "HOOD_ID": 2799.000000, "HOOD_NAME": "Overtown", "MARKET_ID": "MK1245000", "MARKET": "Miami", "STATE": "12", "STATENAME": "Florida", "LATITUDE": 25.784659, "LONGITUDE": -80.202625, "AREA": 1.495920, "HLEVEL": 2.000000, "DATE_ADDED": "2012\/08\/04", "FLAG1": 0, "OB_GEO_ID": "NH2799" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -80.21463341110001, 25.782154451300002 ], [ -80.21588353300001, 25.782696872700001 ], [ -80.217973576800006, 25.7833078056 ], [ -80.219539583200003, 25.784199528800002 ], [ -80.211531118000011, 25.787386122500003 ], [ -80.20836940560001, 25.789128957700001 ], [ -80.206422272200001, 25.789848709300003 ], [ -80.2060101207, 25.7907922853 ], [ -80.206013661300005, 25.793566844899999 ], [ -80.206013794, 25.7968569831 ], [ -80.202368489099996, 25.796952708299997 ], [ -80.202379, 25.797313 ], [ -80.199836, 25.797309 ], [ -80.199819759600004, 25.7970196375 ], [ -80.1993398571, 25.797032239699998 ], [ -80.193583490500004, 25.797234161599999 ], [ -80.193806159800005, 25.796203267299997 ], [ -80.194272724399994, 25.7951752727 ], [ -80.193944, 25.795182 ], [ -80.194266, 25.793434 ], [ -80.195336, 25.789592 ], [ -80.195534, 25.787847 ], [ -80.195514, 25.778409 ], [ -80.195969425200005, 25.778397321299998 ], [ -80.19557104899999, 25.773179598799999 ], [ -80.195360063199999, 25.768486166300001 ], [ -80.196768768399991, 25.7682545324 ], [ -80.198226099099998, 25.768721241800002 ], [ -80.199164023899996, 25.769800189500003 ], [ -80.199997701599997, 25.770738292499999 ], [ -80.200414826200003, 25.772286616100001 ], [ -80.200936435800003, 25.773272690900001 ], [ -80.202343232900006, 25.7749143389 ], [ -80.204375245, 25.776884093299998 ], [ -80.205990323199998, 25.777259031 ], [ -80.206835373600001, 25.777897973199998 ], [ -80.207587, 25.777601 ], [ -80.210881, 25.78 ], [ -80.21463341110001, 25.782154451300002 ] ] ] } },
{ "type": "Feature", "properties": { "HOOD_ID": 2169.000000, "HOOD_NAME": "Church District", "MARKET_ID": "MK1235000", "MARKET": "Jacksonville", "STATE": "12", "STATENAME": "Florida", "LATITUDE": 30.332174, "LONGITUDE": -81.660212, "AREA": 0.131745, "HLEVEL": 1.000000, "DATE_ADDED": "2012\/08\/04", "FLAG1": 0, "OB_GEO_ID": "NH2169" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -81.664799, 30.331204 ], [ -81.663868, 30.334826 ], [ -81.655617, 30.333239 ], [ -81.656717, 30.329439 ], [ -81.664799, 30.331204 ] ] ] } }
}
Large files can best be parsed using an event-based JSON parser (here I use one by kuma-giyomu). The idea is to use callbacks when a certain token is encountered, so that the processing of the data can be done in between parsing.
In the following code, the property "coordinates" is used to trigger the creation of a new polygon object, and then the start function of the array handler to start a new coordinate array and it is submitted to the polygon object when an array end token is encountered.
<?php
include "JSONParser.php";
class Polygon {
public $coordinates = array();
}
$coords = null;
$polygons = array();
$polygon = null;
$j = new JSONParser();
$j->setPropertyHandler(function($value, $property) {
global $polygons, $polygon;
if ($value != "coordinates") {
if (!is_null($polygon)) {
$polygons[] = $polygon;
$polygon = null;
}
return;
}
if (is_null($polygon)) {
$polygon = new Polygon;
}
});
$j->setArrayHandlers(function($value, $property) {
global $coords, $polygon;
if (!is_null($polygon)) {
$coords = array();
}
}, function($value, $property) {
global $coords, $polygon;
if (!is_null($coords)) {
if (!is_null($polygon)) {
$polygon->coordinates[] = $coords;
}
$coords = null;
}
});
$j->setScalarHandler(function($value, $property) {
global $coords;
if (!is_null($coords)) {
$coords[] = $value;
}
});
try {
$j->parseDocument("test.json");
} catch (JSONParserException $e) {
}
if (!is_null($polygon)) {
$polygons[] = $polygon;
$polygon = null;
}
print_r($polygons);
outputs
Array
(
[0] => Polygon Object
(
[coordinates] => Array
(
[0] => Array
(
[0] => -80.21463341110001
[1] => 25.782154451300002
)
[1] => Array
(
[0] => -80.21588353300001
[1] => 25.782696872700001
)
[...]
How do I insert and extract the following from a MySQL database using php. I have tried 'Multiploygon, Multilinestring, GeometryCollection' but cannot get the correct output as below.
1) JSON file to insert
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "GID": 4728339, "PRCL_KEY": "0000T0JT005300000056000010", "PRCL_TYPE": "E", "LSTATUS": "R", "WSTATUS": "C", "GEOM_AREA": 1558.723715, "COMMENTS": "", "TAG_X": 30.920674, "TAG_Y": -25.452585, "TAG_VALUE": "1\/56", "TAG_SIZE": 0.000020, "TAG_ANGLE": 6.282645, "TAG_JUST": "MC", "ID": "T0JT00530000005600001", "DATE_STAMP": "2010\/10\/05" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 30.920838, -25.452746 ], [ 30.920876, -25.452431 ], [ 30.920876, -25.452431 ], [ 30.921498, -25.452367 ], [ 30.921498, -25.452367 ], [ 30.921492, -25.452341 ], [ 30.921492, -25.452341 ], [ 30.920476, -25.452445 ], [ 30.920476, -25.452445 ], [ 30.920441, -25.452719 ], [ 30.920441, -25.452719 ], [ 30.920838, -25.452746 ], [ 30.920838, -25.452746 ] ] ] } }
,
{ "type": "Feature", "properties": { "GID": 4822420, "PRCL_KEY": "0000T0JU004000004445000000", "PRCL_TYPE": "E", "LSTATUS": "R", "WSTATUS": "C", "GEOM_AREA": 391.799538, "COMMENTS": "", "TAG_X": 31.337096, "TAG_Y": -25.508292, "TAG_VALUE": "4445", "TAG_SIZE": 0.000020, "TAG_ANGLE": 0.002299, "TAG_JUST": "MC", "ID": "T0JU00400000444500000", "DATE_STAMP": "2013\/05\/22" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 31.336972, -25.508217 ], [ 31.337103, -25.508419 ], [ 31.337103, -25.508419 ], [ 31.337234, -25.508350 ], [ 31.337234, -25.508350 ], [ 31.337101, -25.508149 ], [ 31.337101, -25.508149 ], [ 31.336972, -25.508217 ], [ 31.336972, -25.508217 ] ] ] } }
2) Output needed
{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"properties":{"name":"T0IS00210000007100000"},"type":"Polyline","coordinates":[29.245262,-26.95622,29.245272,-26.956412,29.245272,-26.956412,29.245282,-26.956603,29.245282,-26.956603,29.245826,-26.956581,29.245826,-26.956581,29.246128,-26.956398,29.246128,-26.956398]}},{"type":"Feature","geometry":{"properties":{"name":"T0IS00210000007300000"},"type":"Polyline","coordinates":[29.245211,-26.955206,29.245231,-26.955589,29.245231,-26.955589,29.246086,-26.955554,29.246086,-26.955554,29.246066,-26.95517,29.246066,-26.95517,29.245211,-26.955206,29.245211,-26.955206]}},{"type":"Feature","geometry":{"properties":{"name":"T0IS00210000007500000"},"type":"Polyline","coordinates":[29.245171,-26.954439,29.245191,-26.954822,29.245191,-26.954822,29.246047,-26.954787,29.246047,-26.954787,29.246037,-26.954594,29.246037,-26.954594,29.245558,-26.954614,29.245558,-26.954614]}},{"type":"Feature","geometry":{"properties":{"name":"T0IS00210000010200000"},"type":"Polyline","coordinates":[29.2436,-26.954444,29.243605,-26.95454,29.243605,-26.95454,29.243623,-26.954887,29.243623,-26.954887,29.244051,-26.95487,29.244051,-26.95487,29.244028,-26.954427,29.244028,-26.954427]}},{"type":"Feature","geometry":{"properties":{"name":"T0IS00210000030400000"},"type":"Polyline","coordinates":[29.242942,-26.949925,29.242963,-26.950314,29.242963,-26.950314,29.243388,-26.950298,29.243388,-26.950298,29.243374,-26.950036,29.243374,-26.950036,29.243367,-26.949915,29.243367,-26.949915]}},{"type":"Feature","geometry":{"properties":{"name":"T0IS00210000010400001"},"type":"Polyline","coordinates":[29.243429,-26.951122,29.243439,-26.951314,29.243439,-26.951314,29.243867,-26.951296,29.243867,-26.951296,29.243857,-26.951105,29.243857,-26.951105,29.243477,-26.95112,29.243477,-26.95112]}},{"type":"Feature","geometry":{"properties":{"name":"T0IS00210000010500000"},"type":"Polyline","coordinates":[29.243288,-26.956694,29.243309,-26.957098,29.243309,-26.957098,29.243328,-26.95746,29.243328,-26.95746,29.243755,-26.957443,29.243755,-26.957443,29.243716,-26.956676,29.243716,-26.956676]}},{"type":"Feature","geometry":{"properties":{"name":"T0IS00210000010600000"},"type":"Polyline","coordinates":[29.243261,-26.956168,29.243288,-26.956694,29.243288,-26.956694,29.243716,-26.956676,29.243716,-26.956676,29.243697,-26.956312,29.243697,-26.956312,29.243688,-26.956151,29.243688,-26.956151]}},{"type":"Feature","geometry":{"properties":{"name":"T0IS00210000010800000"},"type":"Polyline","coordinates":[29.243178,-26.954558,29.243195,-26.954905,29.243195,-26.954905,29.243304,-26.954901,29.243304,-26.954901,29.243623,-26.954887,29.243623,-26.954887,29.243605,-26.95454,29.243605,-26.95454]}},{"type":"Feature","geometry":{"properties":{"name":"T0IS00210000009400000"},"type":"Polyline","coordinates":[29.244647,-26.952287,29.244653,-26.952395,29.244653,-26.952395,29.244682,-26.952394,29.244682,-26.952394,29.244697,-26.952669,29.244697,-26.952669,29.245078,-26.952654,29.245078,-26.952654]}},{"type":"Feature","geometry":{"properties":{"name":"T0IS00210000009500000"},"type":"Polyline","coordinates":[29.244599,-26.95165,29.244609,-26.951846,29.244609,-26.951846,29.244652,-26.951844,29.244652,-26.951844,29.244661,-26.952032,29.244661,-26.952032,29.244825,-26.952025,29.244825,-26.952025]}},{"type":"Feature","geometry":{"properties":{"name":"T0IS00210000009800000"},"type":"Polyline","coordinates":[29.244753,-26.950491,29.244773,-26.950875,29.244773,-26.950875,29.244987,-26.950866,29.244987,-26.950866,29.244967,-26.950483,29.244967,-26.950483,29.244753,-26.950491,29.244753,-26.950491]}}
3) Current PHP code
$geojson = array( 'type' => 'FeatureCollection', 'features' => array() );
while($row = mysql_fetch_assoc($dbquery)) {
$feature = array(
'type' => 'Feature',
'geometry' => array(
'properties' => array(
'name' => $row['LINK_ID']),
'type' => 'Polyline',
'coordinates' => array((float)$row['lon1'],(float)$row['lat1'],(float)$row['lon2'],(float)$row['lat2'],(float)$row['lon3'],(float)$row['lat3'],(float)$row['lon4'],(float)$row['lat4'],(float)$row['lon5'],(float)$row['lat5'],(float)$row['lon6'],(float)$row['lat6'],(float)$row['lon7'],(float)$row['lat7'],(float)$row['lon8'],(float)$row['lat8'],(float)$row['lon9'],(float)$row['lat9'])
)
);
// array_push($geojson, $feature);
array_push($geojson['features'], $feature);
Thank you
Unfortunately, MySQL does not have a native ST_AsGeoJSON function like PostGIS. Fortunately, you can use geoPHP in combination with a little script I wrote to achieve the same result.
Export your GeoJSON file to a MySQL spatial table using OGRor QGIS.
Download geoPHP and my MySQL to GeoJSON script.
Fill in the proper db connection settings and this script should output your MySQL spatial table in proper GeoJSON format.