J'utilise mongoDB
dans lequel j'ai une collection de format suivant.
{"id" : 1 , name : x ttm : 23 , val : 5 }
{"id" : 1 , name : x ttm : 34 , val : 1 }
{"id" : 1 , name : x ttm : 24 , val : 2 }
{"id" : 2 , name : x ttm : 56 , val : 3 }
{"id" : 2 , name : x ttm : 76 , val : 3 }
{"id" : 3 , name : x ttm : 54 , val : 7 }
Sur cette collection, j'ai demandé à obtenir des enregistrements dans l'ordre décroissant comme ceci:
db.foo.find({"id" : {"$in" : [1,2,3]}}).sort(ttm : -1).limit(3)
Mais cela donne deux enregistrements du même id = 1
et je veux des enregistrements tels que cela donne 1 enregistrement par id
.
Est-ce possible dans mongodb?
Il existe une commande distinct
dans mongodb, qui peut être utilisée conjointement avec une requête. Cependant, je crois que cela renvoie simplement une liste distincte de valeurs pour une clé spécifique que vous nommez (c'est-à-dire dans votre cas, vous ne recevrez que les valeurs id), donc je ne suis pas sûr que cela vous donnera exactement ce que vous voulez si vous besoin de tous les documents - vous pourriez avoir besoin de MapReduce à la place.
Documentation sur distinct: http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Distinct
Vous souhaitez utiliser l'agrégation. Vous pouvez faire ça comme ceci:
db.test.aggregate([
// each Object is an aggregation.
{
$group: {
originalId: {$first: '$_id'}, // Hold onto original ID.
_id: '$id', // Set the unique identifier
val: {$first: '$val'},
name: {$first: '$name'},
ttm: {$first: '$ttm'}
}
}, {
// this receives the output from the first aggregation.
// So the (originally) non-unique 'id' field is now
// present as the _id field. We want to rename it.
$project:{
_id : '$originalId', // Restore original ID.
id : '$_id', //
val : '$val',
name: '$name',
ttm : '$ttm'
}
}
])
Ce sera très rapide ... ~ 90ms pour ma base de données de test de 100 000 documents.
Exemple:
db.test.find()
// { "_id" : ObjectId("55fb595b241fee91ac4cd881"), "id" : 1, "name" : "x", "ttm" : 23, "val" : 5 }
// { "_id" : ObjectId("55fb596d241fee91ac4cd882"), "id" : 1, "name" : "x", "ttm" : 34, "val" : 1 }
// { "_id" : ObjectId("55fb59c8241fee91ac4cd883"), "id" : 1, "name" : "x", "ttm" : 24, "val" : 2 }
// { "_id" : ObjectId("55fb59d9241fee91ac4cd884"), "id" : 2, "name" : "x", "ttm" : 56, "val" : 3 }
// { "_id" : ObjectId("55fb59e7241fee91ac4cd885"), "id" : 2, "name" : "x", "ttm" : 76, "val" : 3 }
// { "_id" : ObjectId("55fb59f9241fee91ac4cd886"), "id" : 3, "name" : "x", "ttm" : 54, "val" : 7 }
db.test.aggregate(/* from first code snippet */)
// output
{
"result" : [
{
"_id" : ObjectId("55fb59f9241fee91ac4cd886"),
"val" : 7,
"name" : "x",
"ttm" : 54,
"id" : 3
},
{
"_id" : ObjectId("55fb59d9241fee91ac4cd884"),
"val" : 3,
"name" : "x",
"ttm" : 56,
"id" : 2
},
{
"_id" : ObjectId("55fb595b241fee91ac4cd881"),
"val" : 5,
"name" : "x",
"ttm" : 23,
"id" : 1
}
],
"ok" : 1
}
AVANTAGES: C'est certainement la méthode la plus rapide.
CONTRE: implique l'utilisation de l'API d'agrégation compliquée. En outre, il est étroitement lié au schéma d'origine du document. Cependant, il peut être possible de généraliser cela.
Le problème est que vous souhaitez distiller 3 enregistrements correspondants jusqu'à un sans fournir de logique dans la requête pour savoir comment choisir entre les résultats correspondants.
Vos options sont essentiellement de spécifier une logique d'agrégation d'une certaine sorte (sélectionnez la valeur max ou min pour chaque colonne, par exemple), ou d'exécuter une requête distincte de sélection et de sélectionner uniquement les champs que vous souhaitez être distincts.
querymongo.com fait un bon travail de traduction de ces requêtes distinctes pour vous (de SQL à MongoDB).
Par exemple, ce SQL:
SELECT DISTINCT columnA FROM collection WHERE columnA > 5
Est renvoyé comme ce MongoDB:
db.runCommand({
"distinct": "collection",
"query": {
"columnA": {
"$gt": 5
}
},
"key": "columnA"
});
Je pense que vous pouvez utiliser des agrégats comme celui-ci
collection.aggregate({
$group : {
"_id" : "$id",
"docs" : {
$first : {
"name" : "$name",
"ttm" : "$ttm",
"val" : "$val",
}
}
}
});
Si vous voulez écrire le résultat distinct dans un fichier en utilisant javascript ... c'est comme ça que vous faites
cursor = db.myColl.find({'fieldName':'fieldValue'})
var Arr = new Array();
var count = 0;
cursor.forEach(
function(x) {
var temp = x.id;
var index = Arr.indexOf(temp);
if(index==-1)
{
printjson(x.id);
Arr[count] = temp;
count++;
}
})