Spring Data mongodb日期范围查询

时间:2014-10-03 09:31:31

标签: java mongodb spring-data

我正在使用mongodb的spring数据来创建一个应用程序。

我有这个对象:

public class Room {
    private String name;
    private List<Date> occupied;
}

我希望使用mongodbTemplate来获取未占用日期范围的房间列表。

因此,例如,如果我有一个开始日期10/10/2014和结束日期15/10/2014我想得到列表中没有的房间列表占用日期10,11,12,13 ,2014年10月14,15。

有没有人对此有任何想法?

更新

通过使用此查询,我找到了一种方法:

query.addCriteria(Criteria.where("occupiedDates")
   .ne(from).andOperator(
       Criteria.where("occupiedDates").ne(to))
);
问题是我无法动态添加andOperator。

如果可能的话,我更愿意在标准内添加日期列表。

示例文档是(mongo中只存在一条记录):

  

房间(床数= 1,床型1 = 1,床型2 = 0,床型3 = 0,床型4 = 0,
  filetype = null,noofrooms = 0,occupancy = 0,photo = null,rateid = 1,
  roomname = null,roomno = 888,status = null,
  roomTypeID = 26060747427845848211948325568,occupiedDates = [Sun Aug 10
  00:00:00 EEST 2014,Mon Aug 11 00:00:00 EEST 2014,8月12日00:00:00
  EEST 2014,8月13日星期三00:00:00 EEST 2014],attributes = {})

这是构建wyeru的代码:

SimpleDateFormat dateFormat = new SimpleDateFormat("dd-M-yyyy hh:mm:ss");
Date to = null;
Date from = null;
try {
    to = dateFormat.parse("12-08-2014 00:00:00");
    from = dateFormat.parse("10-08-2014 00:00:00");
} catch (ParseException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
DBObject c1 = new BasicDBObject("occupied", null);
DBObject c2 = BasicDBObjectBuilder.start()
    .push("occupied").push("$not")
    .push("$elemMatch").add("$gte", from).add("$lte", to).get();

Criteria c = Criteria.where("$or").is(Arrays.asList(c1, c2));
Query query = new Query().addCriteria(c);
List<Room> rooms = mongoTemplate.find(query, Room.class);

此查询发送到mongodb

{ "$or" : [
  { "occupied" :  null } ,
  { "occupied" :
    { "$not" :
      { "$elemMatch" :
        { "$gte" : { "$date" : "2014-08-09T21:00:00.000Z"} ,
          "$lte" : { "$date" : "2014-08-11T21:00:00.000Z"}
        }
      }
    } 
  }
]}

从中我们知道查询应该什么也不返回。但它让我回到了一排。

2 个答案:

答案 0 :(得分:1)

根据我最终理解的要求,您想要获取其中的所有文档 occupied的任何元素都不属于指定的日期范围。

在mongo shell上完成:

db.b.find({
    $or : [{
        occupied : null
    }, {
        occupied : {
            $not : {
                $elemMatch : {
                    $gte : start,
                    $lte : end
                }
            }
        }
    }]
}).pretty();

然后转换为Java代码,如下所示:

// Because "Criteria" has a bug when invoking its method "elemMatch", 
// so I build the criteria by the driver directly, almost.  

DBObject c1 = new BasicDBObject("occupied", null);
DBObject c2 = BasicDBObjectBuilder.start().push("occupied").push("$not").
                        push("$elemMatch").add("$gte", start).add("$lte", end).get();
Criteria c = where("$or").is(Arrays.asList(c1, c2));
Query query = new Query().addCriteria(c);
List<Room> rooms = mongoTemplate.find(query, Room.class);

答案 1 :(得分:0)

分析路由

根据您的问题,假设有以下资源:

  • 占用= [d1,d2,d3,d4,d5]; //为了更容易表示,假设元素按升序排列
  • range = [start,end];

因此,您希望在按升序排序后,如果其数据满足以下条件之一,则返回每个文档:

  • start,end,d1,d2,d3,d4,d5 //相当于:min(占用)&gt;端
  • d1,d2,d3,d4,d5,start,end //相当于:max(占用)&lt;启动

如果元素按占用顺序存储,则很容易获取最小值和最大值。 但是你没有提到它,所以我认为它们本身并不合适。

不幸的是,没有运算符可以在标准查询中从数组中获取最小值或最大值。 但是根据标准查询对比数组字段的特性, 如果至少有一个元素或其自身满足标准,则匹配将返回true; 返回false只会使所有标准都失败 很幸运地发现min(occupied) > end等同于NOT (at least one element <= end),这是通过以下方法实现的关键点。

实现mongo shell:

db.b.find({
    $or: [{
        occupied: {
            $not: {
                $lte: end
            }
        }
    }, {
        occupied: {
            $not: {
                $gte: start
            }
        }
    }]
}). pretty();

然后翻译成这样的Java代码:

Criteria c = new Criteria().orOperator(where("occupied").not().lte(end),
        where("occupied").not().gte(start));
Query query = new Query().addCriteria(c);
List<Room> rooms = mongoTemplate.find(query, Room.class);