#mongodb
#mongodb
Вопрос:
У меня есть рекурсивная структура документа mongo, которая представляет собой иерархию «событий»:
{
"request": "open|casetype",
"datetime": ISODate("2013-10-10T23:06:37.000Z"),
"type": "pageload",
"totaltime": 4000,
"serverTime": 3000,
"clientTime": 1000,
"cpuTime" : "2000",
"externalTime" : "500",
"dbTime": "500",
"events":[
{
"type": "interaction",
"label": "interaction 1 - load",
"time": "2000",
"events" :[{
"type": "method",
"label": "test method",
"time": "1000",
"events" :[
{ "type": "dbquery", "sql": "select * from x", "time":"100"},
{ "type": "connector", "connectorName": "Google", "time":"200"},
{
"type":"method",
"label":"another method",
"time":800,
"events":[
{ "type": "dbquery", "sql": "select * from y", "time":"500"}
]
}
]
} ]
}
]
}
Я хочу иметь возможность запускать запросы, которые находят и группируют различные типы событий. Например. Найти среднее время для данного dbquery или соединителя. Группируйте соединители по имени соединителя и подсчитывайте количество и т. Д.
Используя следующее (которое я нашел в StackOverflow) Я могу найти полные документы с типом =»X» в любом месте моего документа:
db.pageloads.find(
function () {
var findKey = "type",
findVal = "dbquery";
function inspectObj(doc) {
return Object.keys(doc).some(function(key) {
if ( typeof(doc[key]) == "object" ) {
return inspectObj(doc[key]);
} else {
return ( key == findKey amp;amp; doc[key] == findVal );
}
});
}
return inspectObj(this);
}
)
Однако то, что я действительно хочу, — это просто вложенные документы, содержащие сопоставление, к которым я мог бы затем выполнить агрегацию. На данный момент я не уверен, связана ли моя проблема с самим поиском или структурой документа.
Ответ №1:
В качестве варианта вы можете использовать пользовательскую функцию запроса.
Это пример нахождения среднего времени. Поместите приведенный ниже код в query.js файл:
(function() {
var cursor = db.pageloads.find(),
result = [],
findKey = 'type',
findVal = 'dbquery',
findParam = 'time';
function average(data) {
return sum(data) / data.length;
}
function sum(data) {
var sum = 0;
for (var i = 0; i < data.length; i ) {
sum = parseInt(data[i], 10);
}
return sum;
}
while (cursor.hasNext()) {
function filter(current) {
for (var item in current) {
if (typeof(current[item].events) === 'object') {
var next = current[item].events;
delete current[item].events;
}
if (typeof(current[item][findKey]) !== 'undefined' amp;amp; current[item][findKey] === findVal) {
result.push(current[item][findParam]);
}
}
if (typeof(next) !== 'undefined') {
filter(next);
};
}
filter(cursor.next().events);
};
return average(result); // You can use sum or other function
})();
и запустите:
mongo your_database < query.js --quiet
Вы можете настроить логику агрегирования, изменив параметры и внутренние подфункции.
Конечно, это не чистое решение, но это лучше, чем ничего.