2017-01-04 2 views
0

У меня есть MongoDB, хранящий данные с разных датчиков. Он имеет следующую структуру:Запросить документ и все его вложенные документы, соответствующие условию в mongodb (с использованием пружины)

{ 
    "_id" : 1, 
    "sensorName" : "Heart Rate", 
    "samplePeriod" : 1000, 
    "data" : [ 
      { 
       "timestamp" : NumberLong("1483537204046"), 
       "dataPoints" : [ 68 70 ] 
      }, 
      { 
       "timestamp" : NumberLong("1483537206046"), 
       "dataPoints" : [ 68 70 ] 
      } 
    ] 
} 
{ 
    "_id" : 2, 
    "sensorName" : "Ambient Light", 
    "samplePeriod" : 500, 
    "data" : [ 
      { 
       "timestamp" : NumberLong("1483537204058"), 
       "dataPoints" : [ 56, 54, 54, 54 ] 
      }, 
      { 
       "timestamp" : NumberLong("1483537206058"), 
       "dataPoints" : [ 56, 54, 54, 54 ] 
      } 
    ] 
} 

Сейчас, например, мне нужен «пульс» - документ со всеми его полями и теми его «данные» - вложенные документами, соответствующими условий «метку времени между 1483537204000 и 1483537214000».

У меня уже есть ответ о том, как это сделать в оболочке монго в другом вопросе. См. Этот код:

aggregate([{ 
    $match: { 
     "_id": 1 
    } 
}, { 
    "$project": { 
     "_id": 1, 
     "sensorName": 1, 
     "samplePeriod": 1, 
     "data": { 
      "$filter": { 
       "input": "$data", 
       "as": "result", 
       "cond": { 
        $and: [{ 
         $gte: ["$$result.timestamp", 1483537204000] 
        }, { 
         $lte: ["$$result.timestamp", 1483537214000] 
        }] 
       } 
      } 
     } 
    } 
}]) 

Но как это сделать в данных весны java? Кажется, в весенних данных нет ничего, как $ filter. Есть ли обходной путь?

Насколько эффективен фильтр в любом случае? Можете ли вы подумать о более эффективном/практическом способе структурирования такого рода данных в mongodb?

Заранее благодарен!

+0

Если вы планируете сделать это с весны, я настоятельно рекомендую вам использовать Spring-данные который даст вам методы для обработки таких запросов. – cralfaro

+0

Я уже использую данные весны (это было изменено в тексте). Я только борюсь, создавая новую агрегацию. Я могу «совпадение», «проект», но не «фильтр». – Nas3nmann

+0

Взгляните на это сообщение, я думаю, вам нужно http://stackoverflow.com/questions/34751845/spring-boot-data-and-mongodb-filter-subdocument-array-query – cralfaro

ответ

0

Вам понадобится использовать MongoTemplate, предусмотренный в зависимости от данных весны-монго. В текущей версии версии не поддерживается поддержка $ filter. Используйте AggressionExpression. Включите ниже проект в проект. Используйте версию данных версии 1.8.5 весной монго.

Aggregation aggregation = newAggregation(
     match(Criteria.where("_id").is(1)), 
     project("_id", "sensorName", "samplePeriod").and(new AggregationExpression() { 
      @Override 
      public DBObject toDbObject(AggregationOperationContext aggregationOperationContext) { 
       DBObject filter = new BasicDBObject("input", "$data").append("as", "result").append("cond", 
         new BasicDBObject("$and", Arrays.<Object> asList(new BasicDBObject("$gte", Arrays.<Object> asList("$$result.timestamp", 1483537204000L)), 
           new BasicDBObject("$lte", Arrays.<Object> asList("$$result.timestamp", 1483537214000L))))); 
       return new BasicDBObject("$filter", filter); 
      } 
     }).as("data") 
); 

List<BasicDBObject> dbObjects = monoTemplate.aggregate(aggregation, "collectionname", BasicDBObject.class).getMappedResults(); 
+0

Отлично работает, но вы пропустили «$» перед первыми «данными» в объекте фильтра. Я приму ваш ответ как наиболее практичный, потому что он поддерживает более старые версии весенних данных и не использует «разматывать», что лучше в моем случае использования. Спасибо Sagar – Nas3nmann

0

Я думаю, что такое же может быть достигнуто за счет использования разматывания и дополнительного соответствия. Драйвер весны mongo действительно обеспечивает поддержку для размотки и выглядит немного чище.

aggregate([{ 
$match: { 
    "_id": 1 
    } 
}, { 
    $unwind : "$data" 
},{ 
    $match : {'data.timestamp' : {$gte : 1483537204000, $lte : 1483537214000}} 
}, { 
    $group : { 
     _id : $_id, 
     data : {$push:$data} 
    } 
}]) 
+1

Но расслабляйтесь на больших документах, так как он создает отдельные документы для каждой записи, не так ли? Я бы хотел этого избежать. Что относительно производительности фильтра в сравнении? – Nas3nmann

+0

что заставило вас думать, что расслабление будет медленным? Имо это было бы так же, если бы не быстрее, чем фильтрация на этапе проектирования, где все данные передавались и анализировались по условию. расслабьтесь и дайте нам руку для более сложного маневра. Также, если вы делаете для одного документа, который имеет предел в 16 МБ, вы не сможете увидеть разницу в производительности в любом из них. –

+0

Это не совсем так. Фильтр - это операция на месте. Это может не иметь значения для вашего конкретного случая. Если у вас есть большие документы, производительность будет хитом. Это специальный порт для фильтра. Почему вы хотите расслабиться, когда нет необходимости? – Veeram

0

Расцепители Spring Data MongoDB 1.10 RC1 (Ingalls), 2.0 M2 (Kay) (как письма) имеют added support for $filter, и это может быть реализовано следующим образом:

Aggregation.newAggregation(Entity.class, 
    match(Criteria.where("_id").is(1)), 
    project("sensorName", "samplePeriod") 
     .and(
      filter("data") 
       .as("item") 
       .by(
        GTE.of(field("item.timestamp"), 1483537204000) 
        .LTE.of(field("item.timestamp"), 1483537214000) 
       ) 
     ).as("data") 
    ) 
Смежные вопросы