在 MongoDB 中,提供了几个按位的操作符,它们分别为 $bitsAllClear、$bitsAllSet、$bitsAnyClear 和 $bitsAnySet 操作符,这些操作符详细描述如下:
$bitsAllClear 操作符用来匹配数字或二进制值,查询给出的所有位置对应位的二进制值为 0 的文档。例如:
// 查询字段 age 是否在位置 1 和位置 5 有位清除 db.t_01.find({ "age": { $bitsAllClear:[1,5] } })
$bitsAllSet 操作符用来匹配数字或二进制值,查询给出的所有位置对应位的二进制值为 1 的文档。例如:
// 查询字段 age 是否具有在位置 1 和位置 5 设置的位 1 db.t_01.find({ "age": { $bitsAllSet:[1,5] } })
$bitsAnyClear 操作符用来匹配数字或二进制值,查询给出的一组位置中任意一个位置对应位的二进制值为 0 的文档。例如:
// 查询字段 age 在位置 1 或位置 5 具有位清除的文档 db.t_01.find({ "age": { $bitsAnyClear:[1,5] } })
$bitsAnySet 操作符用来匹配数字或二进制值,查询给出的一组位置中任意一个位置对应位的二进制值为 1 的文档。例如:
// 查询字段 age 在位置 1 或位置 5 为 1 的文档 db.t_01.find({ "age": { $bitsAnySet:[1,5] } })
下面将介绍怎样使用 Criteria 实现按位查询,Criteria.BitwiseCriteriaOperators 接口定义的按位查询方法如下:
Criteria allClear(int numericBitmask) 使用 $bitsAllClear 创建一个 Criteria,以匹配所有给定的比特位置为空(即0)的文档。
Criteria allClear(String bitmask) 使用 $bitsAllClear 创建一个 Criteria,以匹配所有给定的比特位置为空(即0)的文档。
Criteria allClear(List<Integer> positions) 使用 $bitsAllClear 创建一个 Criteria,以匹配所有给定的比特位置为空(即0)的文档。
Criteria anyClear(int numericBitmask) 使用 $bitsAllClear 创建一个 Criteria,以匹配任何给定的比特位置为空(即0)的文档。
Criteria anyClear(String bitmask) 使用 $bitsAllClear 创建一个 Criteria,以匹配任何给定的比特位置为空(即0)的文档。
Criteria anyClear(List<Integer> positions) 使用 $bitsAllClear 创建一个 Criteria,以匹配任何给定的比特位置为空(即0)的文档。
Criteria allSet(int numericBitmask) 使用 $bitsAllSet 创建一个 Criteria,匹配所有给定的比特位置被设置(即1)的文档。
Criteria allSet(String bitmask) 使用 $bitsAllSet 创建一个 Criteria,匹配所有给定的比特位置被设置(即1)的文档。
Criteria allSet(List<Integer> positions) 使用 $bitsAllSet 创建一个 Criteria,匹配所有给定的比特位置被设置(即1)的文档。
Criteria anySet(int numericBitmask) 使用 $bitsAllSet 创建一个 Criteria,以匹配任何给定的比特位置被设置(即1)的文档。
Criteria anySet(String bitmask) 使用 $bitsAnySet 创建一个 Criteria,以匹配任何给定的比特位置被设置(即1)的文档。
Criteria anySet(List<Integer> positions) 使用 $bitsAnySet 创建一个 Criteria,以匹配任何给定的比特位置被设置(即1)的文档。
下面示例将演示怎样使用 Criteria.BitwiseCriteriaOperators 接口的按位查询方法实现按位查询操作,示例如下:
package com.hxstrive.springdata.mongodb; import com.hxstrive.springdata.mongodb.entity.Person; import com.mongodb.client.model.IndexOptions; import org.bson.Document; import org.bson.types.Binary; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.util.Base64Utils; import java.util.Arrays; import java.util.Base64; import java.util.List; /** * 按位查询 * @author hxstrive.com */ @SpringBootTest class CriteriaDemo7 { @Autowired private MongoTemplate mongoTemplate; @BeforeEach public void init() { // 删除集合 mongoTemplate.dropCollection(Person.class); // 准备数据 // 对应年龄的二进制字符串如下: // 27 ==> 00011011 // 30 ==> 00011110 // 47 ==> 00101111 // 20 ==> 00010100 mongoTemplate.insert(Person.builder().id(100).name("Tom").age(27).email("Tom@sina.com") .interests(new String[]{ "basketball" }) .coordinates(new Double[]{ 116.424966, 39.936625 }) .build()); mongoTemplate.insert(Person.builder().id(200).name("Helen").age(30).email("Helen@outlook.com") .interests(new String[]{ "basketball", "badminton" }) .coordinates(new Double[]{ 114.530044, 38.056057 }) .build()); mongoTemplate.insert(Person.builder().id(300).name("Bill").age(47).email("bill@gmail.com") .interests(new String[]{ "football", "badminton" }) .coordinates(new Double[]{ 114.530044, 38.056057 }) .summary("I am a software engineer and I like Java.") .build()); mongoTemplate.insert(Person.builder().id(400).name("Joe").age(20).email("joe@163.com") .interests(new String[]{ "badminton" }) .coordinates(new Double[]{ 114.364468, 30.650303 }) .summary("I'm a pianist.").build()); // 创建索引 String collectionName = mongoTemplate.getCollectionName(Person.class); mongoTemplate.getCollection(collectionName).createIndex( // 为 coordinates 字段创建 2d 类型的索引 new Document("coordinates", "2d"), // 设置索引名为 idx_coordinates,background 指定索引是否应该在后台创建 new IndexOptions().background(false).name("idx_coordinates")); } @Test public void allClear() { // 查询 age 中指定的所有位的值为 0 的文档 // 27 ==> 00011011 // 30 ==> 00011110 // 47 ==> 00101111 // 20 ==> 00010100 匹配 Criteria criteria = Criteria.where("age").bits() .allClear(Arrays.asList(0,1,3)); List<Person> personList = mongoTemplate.query(Person.class) .matching(Query.query(criteria)).all(); for(Person person : personList) { System.out.println(person); } // 结果: // Person(id=400, name=Joe, age=20, email=joe@163.com, summary=I'm a pianist., coordinates=[114.364468, 30.650303], interests=[badminton]) // 根据查询结果可知,成功匹配了 age=20 的文档 // 27、30、47 和 20 几个年龄,只有 20 符合条件,注意:位的位置从右向左数,第一位位置为0 // 20 ==> 00010100 // 76543210 位置 } @Test public void allClear2() { // 查询 age 中指定的所有位的值为 0 的文档 // 27 ==> 00011011 // 30 ==> 00011110 // 47 ==> 00101111 // 20 ==> 00010100 匹配 // 将我们需要指定的位的位值设置位 1,我们将第 0、1、3 为设置位1,如下: // 掩码:00001011 ==> 0x0B Criteria criteria = Criteria.where("age").bits().allClear(0x0B); List<Person> personList = mongoTemplate.query(Person.class) .matching(Query.query(criteria)).all(); for(Person person : personList) { System.out.println(person); } // 结果: // Person(id=400, name=Joe, age=20, email=joe@163.com, summary=I'm a pianist., coordinates=[114.364468, 30.650303], interests=[badminton]) } @Test public void anyClear() { // 查询 age 中指定的任意位的值为 0 的文档 // 27 ==> 00011011 // 30 ==> 00011110 匹配 // 47 ==> 00101111 // 20 ==> 00010100 匹配 Criteria criteria = Criteria.where("age").bits() .anyClear(Arrays.asList(0,1,3)); List<Person> personList = mongoTemplate.query(Person.class) .matching(Query.query(criteria)).all(); for(Person person : personList) { System.out.println(person); } // 结果: // Person(id=200, name=Helen, age=30, email=Helen@outlook.com, summary=null, coordinates=[114.530044, 38.056057], interests=[basketball, badminton]) // Person(id=400, name=Joe, age=20, email=joe@163.com, summary=I'm a pianist., coordinates=[114.364468, 30.650303], interests=[badminton]) } @Test public void allSet() { // 查询 age 中指定的所有位的值为 1 的文档 // 27 ==> 00011011 // 30 ==> 00011110 // 47 ==> 00101111 匹配 // 20 ==> 00010100 Criteria criteria = Criteria.where("age").bits() .allSet(Arrays.asList(0,5)); List<Person> personList = mongoTemplate.query(Person.class) .matching(Query.query(criteria)).all(); for(Person person : personList) { System.out.println(person); } // 结果: // Person(id=300, name=Bill, age=47, email=bill@gmail.com, summary=I am a software engineer and I like Java., coordinates=[114.530044, 38.056057], interests=[football, badminton]) } @Test public void anySet() { // 查询 age 中指定的所有位的值为 1 的文档 // 27 ==> 00011011 匹配 // 30 ==> 00011110 // 47 ==> 00101111 匹配 // 20 ==> 00010100 Criteria criteria = Criteria.where("age").bits() .anySet(Arrays.asList(0,5)); List<Person> personList = mongoTemplate.query(Person.class) .matching(Query.query(criteria)).all(); for(Person person : personList) { System.out.println(person); } // 结果: // Person(id=100, name=Tom, age=27, email=Tom@sina.com, summary=null, coordinates=[116.424966, 39.936625], interests=[basketball]) // Person(id=300, name=Bill, age=47, email=bill@gmail.com, summary=I am a software engineer and I like Java., coordinates=[114.530044, 38.056057], interests=[football, badminton]) } }
其中,Person 实体代码如下:
package com.hxstrive.springdata.mongodb.entity; import lombok.Builder; import lombok.Data; import lombok.ToString; @Data @ToString @Builder public class Person { /** 用户ID */ private int id; /** 用户姓名 */ private String name; /** 年龄 */ private int age; /** 电子邮件 */ private String email; /** 个人说明 */ private String summary; /** 经纬度信息 */ private Double[] coordinates; /** 个人兴趣 */ private String[] interests; }