Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yii2
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PSDI Army
yii2
Commits
a3f5236e
Commit
a3f5236e
authored
Dec 03, 2013
by
Paul Klimov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Mongo Collection "group" and "mapReduce" functions fixed.
parent
10bdd6b8
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
136 additions
and
27 deletions
+136
-27
Collection.php
extensions/mongo/Collection.php
+80
-25
CollectionTest.php
tests/unit/extensions/mongo/CollectionTest.php
+56
-2
No files found.
extensions/mongo/Collection.php
View file @
a3f5236e
...
@@ -365,7 +365,7 @@ class Collection extends Object
...
@@ -365,7 +365,7 @@ class Collection extends Object
}
}
/**
/**
* Performs aggregation using Mongo
Map Reduce mechanism
.
* Performs aggregation using Mongo
"group" command
.
* @param mixed $keys fields to group by. If an array or non-code object is passed,
* @param mixed $keys fields to group by. If an array or non-code object is passed,
* it will be the key used to group results. If instance of [[\MongoCode]] passed,
* it will be the key used to group results. If instance of [[\MongoCode]] passed,
* it will be treated as a function that returns the key to group by.
* it will be treated as a function that returns the key to group by.
...
@@ -377,37 +377,92 @@ class Collection extends Object
...
@@ -377,37 +377,92 @@ class Collection extends Object
* - condition - criteria for including a document in the aggregation.
* - condition - criteria for including a document in the aggregation.
* - finalize - function called once per unique key that takes the final output of the reduce function.
* - finalize - function called once per unique key that takes the final output of the reduce function.
* @return array the result of the aggregation.
* @return array the result of the aggregation.
* @see http://docs.mongodb.org/manual/core/map-reduce/
* @see http://docs.mongodb.org/manual/reference/command/group/
* @throws Exception on failure.
*/
*/
public
function
mapReduce
(
$keys
,
$initial
,
$reduce
,
$options
=
[])
public
function
group
(
$keys
,
$initial
,
$reduce
,
$options
=
[])
{
{
$token
=
'
Map reduce
from '
.
$this
->
getFullName
();
$token
=
'
Grouping
from '
.
$this
->
getFullName
();
Yii
::
info
(
$token
,
__METHOD__
);
Yii
::
info
(
$token
,
__METHOD__
);
Yii
::
beginProfile
(
$token
,
__METHOD__
);
try
{
Yii
::
beginProfile
(
$token
,
__METHOD__
);
if
(
!
(
$reduce
instanceof
\MongoCode
))
{
if
(
!
(
$reduce
instanceof
\MongoCode
))
{
$reduce
=
new
\MongoCode
((
string
)
$reduce
);
$reduce
=
new
\MongoCode
((
string
)
$reduce
);
}
if
(
array_key_exists
(
'condition'
,
$options
))
{
$options
[
'condition'
]
=
$this
->
buildCondition
(
$options
[
'condition'
]);
}
if
(
array_key_exists
(
'finalize'
,
$options
))
{
if
(
!
(
$options
[
'finalize'
]
instanceof
\MongoCode
))
{
$options
[
'finalize'
]
=
new
\MongoCode
((
string
)
$options
[
'finalize'
]);
}
}
if
(
array_key_exists
(
'condition'
,
$options
))
{
$options
[
'condition'
]
=
$this
->
buildCondition
(
$options
[
'condition'
]);
}
if
(
array_key_exists
(
'finalize'
,
$options
))
{
if
(
!
(
$options
[
'finalize'
]
instanceof
\MongoCode
))
{
$options
[
'finalize'
]
=
new
\MongoCode
((
string
)
$options
[
'finalize'
]);
}
}
// Avoid possible E_DEPRECATED for $options:
if
(
empty
(
$options
))
{
$result
=
$this
->
mongoCollection
->
group
(
$keys
,
$initial
,
$reduce
);
}
else
{
$result
=
$this
->
mongoCollection
->
group
(
$keys
,
$initial
,
$reduce
,
$options
);
}
$this
->
tryResultError
(
$result
);
Yii
::
endProfile
(
$token
,
__METHOD__
);
if
(
array_key_exists
(
'retval'
,
$result
))
{
return
$result
[
'retval'
];
}
else
{
return
[];
}
}
catch
(
\Exception
$e
)
{
Yii
::
endProfile
(
$token
,
__METHOD__
);
throw
new
Exception
(
$e
->
getMessage
(),
(
int
)
$e
->
getCode
(),
$e
);
}
}
// Avoid possible E_DEPRECATED for $options:
}
if
(
empty
(
$options
))
{
$result
=
$this
->
mongoCollection
->
group
(
$keys
,
$initial
,
$reduce
);
}
else
{
$result
=
$this
->
mongoCollection
->
group
(
$keys
,
$initial
,
$reduce
,
$options
);
}
Yii
::
endProfile
(
$token
,
__METHOD__
);
/**
if
(
array_key_exists
(
'retval'
,
$result
))
{
* Performs aggregation using Mongo "map reduce" mechanism.
return
$result
[
'retval'
];
* Note: this function will not return the aggregation result, instead it will
}
else
{
* write it inside the another Mongo collection specified by "out" parameter.
return
[];
* @param \MongoCode|string $map function, which emits map data from collection.
* Argument will be automatically cast to [[\MongoCode]].
* @param \MongoCode|string $reduce function that takes two arguments (the map key
* and the map values) and does the aggregation.
* Argument will be automatically cast to [[\MongoCode]].
* @param string|array $out output collection name. It could be a string for simple output
* ('outputCollection'), or an array for parametrized output (['merge' => 'outputCollection'])
* @param array $condition criteria for including a document in the aggregation.
* @return string the map reduce output collection name.
* @throws Exception on failure.
*/
public
function
mapReduce
(
$map
,
$reduce
,
$out
,
$condition
=
[])
{
$token
=
'Map reduce from '
.
$this
->
getFullName
();
Yii
::
info
(
$token
,
__METHOD__
);
try
{
Yii
::
beginProfile
(
$token
,
__METHOD__
);
if
(
!
(
$map
instanceof
\MongoCode
))
{
$map
=
new
\MongoCode
((
string
)
$map
);
}
if
(
!
(
$reduce
instanceof
\MongoCode
))
{
$reduce
=
new
\MongoCode
((
string
)
$reduce
);
}
$command
=
[
'mapReduce'
=>
$this
->
getName
(),
'map'
=>
$map
,
'reduce'
=>
$reduce
,
'out'
=>
$out
];
if
(
!
empty
(
$condition
))
{
$command
[
'query'
]
=
$this
->
buildCondition
(
$condition
);
}
$result
=
$this
->
mongoCollection
->
db
->
command
(
$command
);
$this
->
tryResultError
(
$result
);
Yii
::
endProfile
(
$token
,
__METHOD__
);
return
$result
[
'result'
];
}
catch
(
\Exception
$e
)
{
Yii
::
endProfile
(
$token
,
__METHOD__
);
throw
new
Exception
(
$e
->
getMessage
(),
(
int
)
$e
->
getCode
(),
$e
);
}
}
}
}
...
...
tests/unit/extensions/mongo/CollectionTest.php
View file @
a3f5236e
...
@@ -10,6 +10,7 @@ class CollectionTest extends MongoTestCase
...
@@ -10,6 +10,7 @@ class CollectionTest extends MongoTestCase
protected
function
tearDown
()
protected
function
tearDown
()
{
{
$this
->
dropCollection
(
'customer'
);
$this
->
dropCollection
(
'customer'
);
$this
->
dropCollection
(
'mapReduceOut'
);
parent
::
tearDown
();
parent
::
tearDown
();
}
}
...
@@ -157,7 +158,7 @@ class CollectionTest extends MongoTestCase
...
@@ -157,7 +158,7 @@ class CollectionTest extends MongoTestCase
/**
/**
* @depends testBatchInsert
* @depends testBatchInsert
*/
*/
public
function
test
MapReduce
()
public
function
test
Group
()
{
{
$collection
=
$this
->
getConnection
()
->
getCollection
(
'customer'
);
$collection
=
$this
->
getConnection
()
->
getCollection
(
'customer'
);
$rows
=
[
$rows
=
[
...
@@ -175,12 +176,65 @@ class CollectionTest extends MongoTestCase
...
@@ -175,12 +176,65 @@ class CollectionTest extends MongoTestCase
$keys
=
[
'address'
=>
1
];
$keys
=
[
'address'
=>
1
];
$initial
=
[
'items'
=>
[]];
$initial
=
[
'items'
=>
[]];
$reduce
=
"function (obj, prev) { prev.items.push(obj.name); }"
;
$reduce
=
"function (obj, prev) { prev.items.push(obj.name); }"
;
$result
=
$collection
->
mapReduce
(
$keys
,
$initial
,
$reduce
);
$result
=
$collection
->
group
(
$keys
,
$initial
,
$reduce
);
$this
->
assertEquals
(
2
,
count
(
$result
));
$this
->
assertEquals
(
2
,
count
(
$result
));
$this
->
assertNotEmpty
(
$result
[
0
][
'address'
]);
$this
->
assertNotEmpty
(
$result
[
0
][
'address'
]);
$this
->
assertNotEmpty
(
$result
[
0
][
'items'
]);
$this
->
assertNotEmpty
(
$result
[
0
][
'items'
]);
}
}
/**
* @depends testBatchInsert
*/
public
function
testMapReduce
()
{
$collection
=
$this
->
getConnection
()
->
getCollection
(
'customer'
);
$rows
=
[
[
'name'
=>
'customer 1'
,
'status'
=>
1
,
'amount'
=>
100
,
],
[
'name'
=>
'customer 2'
,
'status'
=>
1
,
'amount'
=>
200
,
],
[
'name'
=>
'customer 2'
,
'status'
=>
2
,
'amount'
=>
400
,
],
[
'name'
=>
'customer 2'
,
'status'
=>
3
,
'amount'
=>
500
,
],
];
$collection
->
batchInsert
(
$rows
);
$result
=
$collection
->
mapReduce
(
'function () {emit(this.status, this.amount)}'
,
'function (key, values) {return Array.sum(values)}'
,
'mapReduceOut'
,
[
'status'
=>
[
'$lt'
=>
3
]]
);
$this
->
assertEquals
(
'mapReduceOut'
,
$result
);
$outputCollection
=
$this
->
getConnection
()
->
getCollection
(
$result
);
$rows
=
$outputCollection
->
findAll
();
$expectedRows
=
[
[
'_id'
=>
1
,
'value'
=>
300
,
],
[
'_id'
=>
2
,
'value'
=>
400
,
],
];
$this
->
assertEquals
(
$expectedRows
,
$rows
);
}
public
function
testCreateIndex
()
public
function
testCreateIndex
()
{
{
$collection
=
$this
->
getConnection
()
->
getCollection
(
'customer'
);
$collection
=
$this
->
getConnection
()
->
getCollection
(
'customer'
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment