Mongodb получает отдельные записи
Я использую mongoDB
, в котором у меня есть коллекция следующего формата.
{"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 }
В этой коллекции я запросил, чтобы получить записи в порядке убывания следующим образом:
db.foo.find({"id" : {"$in" : [1,2,3]}}).sort(ttm : -1).limit(3)
Но он дает две записи одного и того же id = 1
, и мне нужны записи, которые дают 1 запись за id
.
Возможно ли это в mongodb?
Ответы
Ответ 1
В mongodb есть команда distinct
, которая может использоваться в сочетании с запросом. Тем не менее, я считаю, что это просто возвращает отдельный список значений для определенного имени, которое вы называете (т.е. В вашем случае вы получили бы только возвращаемые значения id), поэтому я не уверен, что это даст вам именно то, что вы хотите, если вы нужны все документы - вместо этого вам может потребоваться MapReduce.
Документация по отдельным:
http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Distinct
Ответ 2
Вы хотите использовать агрегацию. Вы можете сделать это вот так:
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'
}
}
])
Это будет очень быстро... ~ 90 мс для моей тестовой БД из 100 000 документов.
Пример:
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
}
PROS: Почти наверняка самый быстрый метод.
CONS: Использует сложный API агрегирования. Кроме того, он тесно связан с исходной схемой документа. Хотя, возможно, это можно обобщить.
Ответ 3
Проблема заключается в том, что вы хотите перегонять 3 совпадающие записи до единицы без предоставления какой-либо логики в запросе о том, как выбирать между соответствующими результатами.
В основном вы можете указать логику агрегации (например, максимальное или минимальное значение для каждого столбца) или запустить отдельный запрос и выбрать только те поля, которые вы хотите отличать.
querymongo.com отлично работает для перевода этих различных запросов (от SQL к MongoDB).
Например, этот SQL:
SELECT DISTINCT columnA FROM collection WHERE columnA > 5
Возвращается как этот MongoDB:
db.runCommand({
"distinct": "collection",
"query": {
"columnA": {
"$gt": 5
}
},
"key": "columnA"
});
Ответ 4
Я считаю, что вы можете использовать агрегат, подобный этому
collection.aggregate({
$group : {
"_id" : "$id",
"docs" : {
$first : {
"name" : "$name",
"ttm" : "$ttm",
"val" : "$val",
}
}
}
});
Ответ 5
Если вы хотите написать отдельный результат в файле с помощью javascript... так вы делаете
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++;
}
})