2

Я в настоящее время имею этой схемуВозврат Последней Сортировки Даты из нескольких массивов

var dataSchema = new Schema({ 
hid: { type: String }, 
sensors: [{ 
    nid: { type: String }, 
    sid: { type: String }, 
    data: { 
     param1: { type: String }, 
     param2: { type: String }, 
     data: { type: String } 
    }, 
    date: { type: Date, default: Date.now } 
}], 
actuators: [{ 
    nid: { type: String }, 
    aid: { type: String }, 
    control_id: { type: String }, 
    data: { 
     param1: { type: String }, 
     param2: { type: String }, 
     data: { type: String } 
    }, 
    date: { type: Date, default: Date.now } 
}], 
status: [{ 
    nid: {type: String}, 
    status_code: {type: String}, 
    date: { type: Date, default: Date.now } 
}], 
updated: { type: Date, default: Date.now }, 
created: { type: Date } 
}); 

И запрос, который я пытаюсь построить должен искать схему, «спрятался», а затем только выбрать последний объект (по дате) из массивов «датчики», «исполнительные механизмы» и «статус», но я не могу понять, как это сделать.

С помощью этого запроса я могу частично добиться того, что я пытаюсь получить, но только дайте мне один массив в то время, так что я должен запрашивать базу данных в три раза, и я бы избежать этого

db.getCollection('data').aggregate([ 
        { $match : { hid : "testhid" } }, 
        {$project : {"sensors" : 1}}, 
        {$unwind : "$sensors"}, 
        {$sort : {"sensors.date" : -1}}, 
        {$limit : 1} 
       ]) 

Заранее благодарю за любую помощь

+1

Можете ли вы разместить образец данных (тестовые документы) – Saleem

+0

Вы хотите отсортировать его по дате регистрации не только по дате регистрации, но и по дате размещения? Вы можете разматывать несколько раз, но не один раз несколько массивов. Это должно работать в одном запросе. – Clijsters

ответ

1

Лучшим советом здесь будет «хранить» массивы, отсортированные в первую очередь. Скорее всего, они, вероятно, уже считают, что любая операция $push (или даже если вы использовали .push()) на самом деле просто «добавит» к массиву, так что последний элемент «последний» в любом случае.

Так что, если вы на самом деле не «меняете» свойства "date" после того, как создали, то «последняя дата» всегда «последний» элемент в любом случае. В этом случае, просто $slice записи:

Data.find({ "hid": "testhid" }).select({ 
    "sensors": { "$slice": -1 }, 
    "actuators": { "$slice": -1 }, 
    "status": { "$slice": -1 } 
}).exec(function(err,data) { 

]); 

«Если», какой-то причине вы на самом деле не удалось сохранить другим способом или изменили "date" свойства, чтобы они последние уже не «последний», то это вероятно, хорошая идея, чтобы все будущие обновления использовали модификатор $sort с $push. Это может «гарантировать», что дополнения к массиву последовательно сортируются. Вы можете даже изменить всю коллекцию в одном простом утверждении:

Date.update(
    {}, 
    { 
     "$push": { 
      "sensors": { "$each": [], "$sort": { "date": 1 } }, 
      "actuators": { "$each": [], "$sort": { "date": 1 } }, 
      "status": { "$each": [], "$sort": { "date": 1 } } 
     } 
    }, 
    { "multi": true }, 
    function(err,num) { 

    } 
) 

В этом одном заявлении, каждый документ в коллекции того, каждый массив упомянутые повторно сортируется, что «последней датой» является «последним» запись для каждого массива. Это означает, что вышеупомянутое использование $slice прекрасно.


Теперь «Если», абсолютно ничего из этого не возможно для вашего случая, и вы на самом деле есть какая-то причина, почему элементы массива не должны быть обычно хранятся в "date" порядке, а затем (и только действительно тогда) должны вы прибегать к использованию .aggregate() для того, чтобы в результатах:

Data.aggregate(
[ 
    { "$match": { "hid": "testhid" } }, 
    { "$unwind": "$sensors" }, 
    { "$sort": { "_id": 1, "sensors.date": -1 } }, 
    { "$group": { 
     "_id": "$_id", 
     "sensors": { "$first": "$sensors" }, 
     "actuators": { "$first": "$actuators" }, 
     "status": { "$first": "$status" }, 
     "updated": { "$first": "$updated" }, 
     "created": { "$first": "$created" } 
    }}, 
    { "$unwind": "$actuators" }, 
    { "$sort": { "_id": 1, "actuators.date": -1 } }, 
    { "$group": { 
     "_id": "$_id", 
     "sensors": { "$first": "$sensors" }, 
     "actuators": { "$first": "$actuators" }, 
     "status": { "$first": "$status" }, 
     "updated": { "$first": "$updated" }, 
     "created": { "$first": "$created" } 
    }}, 
    { "$unwind": "$status" }, 
    { "$sort": { "_id": 1, "status.date": -1 } }, 
    { "$group": { 
     "_id": "$_id", 
     "sensors": { "$first": "$sensors" }, 
     "actuators": { "$first": "$actuators" }, 
     "status": { "$first": "$status" }, 
     "updated": { "$first": "$updated" }, 
     "created": { "$first": "$created" } 
    }} 
], 
function(err,data) { 

} 
) 

реальность есть то, что MongoDB не имеет возможности «инлайн рода» содержимое массива в возврате из любого оператора трубопровода запроса или агрегации. Вы можете сделать это только с помощью обработки $unwind, используя $sort и, наконец, $group, используя $first, чтобы эффективно получить один элемент из отсортированного массива.

Для этого вам нужно сделать «per» массив, так как процесс $unwind создает отдельные документы для каждого элемента массива. Вы «могли бы» сделать все это в один присест, как:

Data.aggregate(
[ 
    { "$match": { "hid": "testhid" } }, 
    { "$unwind": "$sensors" }, 
    { "$unwind": "$actuators" }, 
    { "$unwind": "$status" } 
    { "$sort": { 
     "_id": 1, 
     "sensors.date": -1, 
     "actuators.date": -1, 
     "actuators.status": -1 
    }}, 
    { "$group": { 
     "_id": "$_id", 
     "sensors": { "$first": "$sensors" }, 
     "actuators": { "$first": "$actuators" }, 
     "status": { "$first": "$status" }, 
     "updated": { "$first": "$updated" }, 
     "created": { "$first": "$created" } 
    }} 
], 
function(err,data) { 

} 
) 

Но это на самом деле не так много улучшений на другой процесс со всеми вещами считаются.


реальный урок здесь должен быть «сохранить массив отсортирован» и затем делать операцию по $slice последний пункт является очень простой процесс.

+0

Большое спасибо за этот полный ответ – danielebuso

+0

Последний вопрос: есть ли способ включить '$ elemMatch: {nid:" 1 "}' при разрезании массива 'sensor'? Я попробовал эти «датчики»: [{$ elemMatch: {nid: "1"}}, {"$ slice": -10}], но это не сработает. Спасибо еще раз за помощь. – danielebuso

+0

@ danielebuso Для этого требуется структура агрегации. В любом случае проекция не может совпадать с одним элементом массива. Но есть более простой способ использования структуры агрегации. ** Но ** это еще один вопрос, и его следует задавать отдельно. –

Смежные вопросы