I am trying to do something that I think is quite simple. Suppose I have a series of records in mongo that have a common key, and variable number of attributes. I want to select
The solution from Stennie requires you to know exactly which attributes you want to return from each matching item in the collection you're querying. This isn't always the case.
We had to solve this problem within a Groovy on Grails application we're writing.
We wrote a method like this to handle the "find by X" requests:
private List<DBObject> findDistinctPages(Map by) {
def command =
new GroupCommand(
(DBCollection) db.pages,
new BasicDBObject(['url': 1]),
new BasicDBObject(by),
new BasicDBObject([:]),
'function ( current, result ) { for(i in current) { result[i] = current[i] } }',
''
)
db.pages.group(command).sort { it.title }
}
And then call it within our code as follows:
def pages = findDistinctPages([$or: [[type: 'channel'], [type: 'main']]])
This works by passing the results of the initial query to the javascript function at the end of the GroupCommand. Mongo only returns the attributes you specify in the initial query and nothing else, so you then have to iterate over the results a 2nd time, populating them with the rest of the data from mongo.
use $addToSet
to the group,it will work
db.data.aggregate(
{ $group : {
_id : "$Name",
x: { $addToSet: "$x" },
y: { $addToSet: "$y" },
z: { $addToSet: "$z" },
}}
)
If you want to combine the attributes, you'll need to add those to the group
. For example, using $addToSet to find the unique values of the x,y,z attributes grouped by each name:
db.data.aggregate(
{ $group : {
_id : "$Name",
x: { $addToSet: "$x" },
y: { $addToSet: "$y" },
z: { $addToSet: "$z" },
}}
)
Returns:
{
"result" : [
{
"_id" : "Rob",
"x" : [
12
],
"y" : [
2
],
"z" : [ ]
},
{
"_id" : "George",
"x" : [
5
],
"y" : [
3
],
"z" : [
9
]
}
],
"ok" : 1
}
Here is the another way of doing it :
$connection = 'mongodb://localhost:27017';
$con = new Mongo($connection); // mongo connection
$db = $con->test; /// database
$collection = $db->prb; // table
$keys = array("Name" => 1,"x"=>1,"y"=>1,"z"=>1);
// set intial values
$initial = array("count" => 0);
// JavaScript function to perform
$reduce = "function (obj, prev) { prev.count++; }";
$g = $collection->group($keys, $initial, $reduce);
echo "<pre>";
print_r($g);
You will get the answer something like this (not the exact output) :
Array
(
[retval] => Array
(
[0] => Array
(
[Name] => George
[x] =>
[y] =>
[z] =>
[count] => 2
)
[1] => Array
(
[Name] => Rob
[x] =>
[y] =>
[z] =>
[count] => 1
)
)
[count] => 5
[keys] => 3
[ok] => 1
)