查询文档及其所有符合 mongodb 条件的子文档(使用 spring)
Query a document and all of its subdocuments that match a condition in mongodb (using spring)
我有一个 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 ]
}
]
}
例如,现在我需要 "Heart Rate" - 包含其所有字段的文档及其 "data" - 匹配条件 "timestamp between 1483537204000 and 1483537214000".
的子文档
我已经在另一个问题的 mongo shell 中找到了如何执行此操作的答案。请参阅此代码:
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 spring-data 中执行此操作? spring-data 中似乎没有 $filter 之类的东西。有解决方法吗?
$filter 的效率如何?
您能想出一种更 efficient/practical 的方法来在 mongodb 中构建此类数据吗?
提前致谢!
您需要使用 spring mongo 数据依赖项中提供的 MongoTemplate。在当前发行版中没有对 $filter 的开箱即用支持。使用 AggressionExpression。在项目中包含以下投影。使用1.8.5springmongo数据版本
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();
我认为使用 unwind 和额外的匹配也可以达到同样的效果。 Spring mongo 驱动程序确实提供了对 unwind 的支持,它看起来更干净了。
aggregate([{
$match: {
"_id": 1
}
}, {
$unwind : "$data"
},{
$match : {'data.timestamp' : {$gte : 1483537204000, $lte : 1483537214000}}
}, {
$group : {
_id : $_id,
data : {$push:$data}
}
}])
Spring Data MongoDB 1.10 RC1 (Ingalls), 2.0 M2 (Kay) releases (as of writing) have 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")
)
我有一个 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 ]
}
]
}
例如,现在我需要 "Heart Rate" - 包含其所有字段的文档及其 "data" - 匹配条件 "timestamp between 1483537204000 and 1483537214000".
的子文档我已经在另一个问题的 mongo shell 中找到了如何执行此操作的答案。请参阅此代码:
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 spring-data 中执行此操作? spring-data 中似乎没有 $filter 之类的东西。有解决方法吗?
$filter 的效率如何? 您能想出一种更 efficient/practical 的方法来在 mongodb 中构建此类数据吗?
提前致谢!
您需要使用 spring mongo 数据依赖项中提供的 MongoTemplate。在当前发行版中没有对 $filter 的开箱即用支持。使用 AggressionExpression。在项目中包含以下投影。使用1.8.5springmongo数据版本
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();
我认为使用 unwind 和额外的匹配也可以达到同样的效果。 Spring mongo 驱动程序确实提供了对 unwind 的支持,它看起来更干净了。
aggregate([{
$match: {
"_id": 1
}
}, {
$unwind : "$data"
},{
$match : {'data.timestamp' : {$gte : 1483537204000, $lte : 1483537214000}}
}, {
$group : {
_id : $_id,
data : {$push:$data}
}
}])
Spring Data MongoDB 1.10 RC1 (Ingalls), 2.0 M2 (Kay) releases (as of writing) have 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")
)