【问题标题】:Spring Data MongoDB, Searching by long valueSpring Data MongoDB,按长值搜索
【发布时间】:2020-02-28 12:41:28
【问题描述】:

我有一个存储在 mongo 中的对象,如下所示(当我查看文档时,它在 RoboMongo 中是这样显示的):

{
    "_id": ObjectId("5e579c8674f69d1c1451f3ae"),
    ...
    "timestamp": NumberLong(1582800002779),
    ...
    "_class": "regular"
}

我存储的对象是这样定义的:

public class MyObjectModel {
    @Id
    @Field(value = ID_FIELD_NAME)
    private String id;
    @Field(value = TIMESTAMP_FIELD_NAME)
    private Long timestamp;
...
}

我的意图是在时间范围内获取对象列表。 这就是我使用 spring data mongo db 创建查询的方式:

    public List<Criteria> generateAllCriteria() {
        List<Criteria> criteriaList = new ArrayList<>();
        Optional.ofNullable(searchCriteria.getFromTimestamp()).map(ts -> criteriaList.add(generateFromTimestampCriteria(ts)));
        Optional.ofNullable(searchCriteria.getToTimestamp()).map(ts -> criteriaList.add(generateToTimestampCriteria(ts)));
        return criteriaList;
    }

    private Criteria generateFromTimestampCriteria(Long fromTimestamp) {
        Criteria critFromTimestamp = Criteria.where(TIMESTAMP_FIELD_NAME).gte(fromTimestamp);
        log.debug("From Timestamp criteria {}", critFromTimestamp.getCriteriaObject().toJson());
        return critFromTimestamp;
    }

    private Criteria generateToTimestampCriteria(Long toTimestamp) {
        Criteria critToTimestamp = Criteria.where(TIMESTAMP_FIELD_NAME).lt(toTimestamp);
        log.debug("To Timestamp criteria {}", critToTimestamp.getCriteriaObject().toJson());
        return critToTimestamp;
    }
...
    List<Criteria> criteriaList = generateAllCriteria();

    Criteria finalCriteria = new Criteria();
    finalCriteria = finalCriteria.andOperator(criteriaList.toArray(new Criteria[criteriaList.size()]));
    log.debug("Final criteria {}", finalCriteria);
    Query query = new Query();
    query.addCriteria(finalCriteria);

    List<MyObjectModel> myObjects = mongoTemplate.find(query, MyObjectModel.class);

当我显示它们时的查询如下:

From Timestamp criteria { "timestamp" : { "$gte" : { "$numberLong" : "1582714365857" } } }
To Timestamp criteria { "timestamp" : { "$lt" : { "$numberLong" : "1582887165858" } } }

而最终的查询条件似乎是这样的:

o.s.data.mongodb.core.MongoTemplate - find using query: { "$and" : [{ "timestamp" : { "$gte" : { "$numberLong" : "1582714365857" } } }, { "timestamp" : { "$lt" : { "$numberLong" : "1582887165858" } } }] } fields: Document{{}} for class: class mypackage.model.MyObjectModel in collection: myObjectModel

乍一看似乎没问题,但是当我手动针对 Mongo 运行它时,它不会返回任何记录,这在我看来意味着它在某种程度上是不正确的。 以下是我在 Mongo 上运行的具体内容:

db.getCollection('my-collection').find({ "$and" : [{ "timestamp" : { "$gte" : { "$numberLong" : "1582707873806" } } }, { "timestamp" : { "$lt" : { "$numberLong" : "1582887165858" } } }] })

而且它显然不返回任何记录。但是当我修改查询并摆脱 $numberLong:

db.getCollection('my-collection').find({ "$and" : [{ "timestamp" : { "$gte" : 1582707873806 } }, { "timestamp" : { "$lt" : 1582887165858 } }] })

它就像一个魅力。

有人可以启发我并解释我做错了什么吗?应该如何以正确的方式完成? 如何使 spring data mongo 创建正确的查询?

不用说字符串和整数工作得很好。它只是关于LONGs。

提前感谢您的帮助。

【问题讨论】:

  • 您的 Spring-Data MongoDB 查询是否运行并返回预期结果?
  • 我不确定我是否理解您的问题。当我如上所述运行我的应用程序 spring data mongodb 查询时,不会返回任何条目。当我从 robomongo 运行查询时,它只有在我提供值时才会返回结果。当我按时间戳搜索时:...{$numberlong:"aNumber"} 它不返回任何内容。
  • 事实上,当从 robomongo 而不是 $numberLong 调用时,应该使用 NumberLong() 函数。然后它工作正常。我在调查我的问题时了解到这一点。
  • 这种方法有效吗?我也面临同样的问题,即 numberlong 被添加到查询参数中并且绝对没有结果。

标签: java spring mongodb spring-data-mongodb


【解决方案1】:

据我了解:

  • from/to 是查询中的唯一参数
  • 都可以为空

并假设您的模型是:

public class Regular {
  @Id
  private String id;

  @Field
  private Long timestamp;
}

那么可能的解决方案(恕我直言更短)是:

// exists(true) is a "hack" to return the elements in case both from/to are null
public List<Regular> find(Long from, Long to) {

  var criteria = where("timestamp").exists(true);
  if(from != null) {
    criteria.gte(from);
  }
  if(to != null) {
    criteria.lte(to);
  }

  return mongoTemplate.find(Query.query(criteria), Regular.class);
}

PS。我已经用 Spring Boot 2.2.4 和 Mongo 3.6 进行了检查。

PS2。您仍然可以通过额外的 if 条件处理 from/to 都为 null 的情况,然后删除 exists(true)。

【讨论】:

  • 你会这么好心并提供mongo模板构建的查询吗?谢谢你。我和你做了同样的事情,但仍然没有得到任何数据。
  • Query.query(criteria).toString() 的结果是:Query: { "timestamp" : { "$exists" : true, "$gte" : { "$numberLong" : "10"}, "$lte" : { "$numberLong" : "20"}}}, Fields: {}, Sort: {}
  • 这也是我得到的......并且由于某种原因它不起作用。我将在本周重新审视这篇文章,如果这有帮助或我必须做的事情,我会回来。谢谢
  • 事情是这样的,我在上面的代码中犯了一个错误。那东西很好用。我有一个扩展常规的类,并且该集合在该类上。在 mongo 模板中,我只想获取那些适合常规类的属性。所以实际上我在 mongoTemplate 上错误地调用了 find 方法。对不起这个错误。事实上,我上面的代码 sn-p 与我在代码中的代码不完全一样。
【解决方案2】:

我找到了解决我面临的同样问题的方法。 我刚刚创建了一个自定义读取转换器,当我从数据库中获取数据时,它将 DATE 值映射到 long 值。 这是我参考的链接 enter link description here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-01
    • 1970-01-01
    • 2018-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多