不知道如何使用 MongoDB 的 $bitsAnySet 运算符
Can't figure out how to use MongoDB's $bitsAnySet operator
我正在做一个小项目,我需要在我的 MongoDB 数据库中存储营业时间。我决定为整个星期使用一个位掩码,由 336 位表示,这意味着每一位代表一天中的 30 分钟。 (使用位掩码没有特殊原因。我愿意改变我存储营业时间的方式,但我很好奇。)
我认为如果我使用 $bitsAnySet 运算符基于位掩码进行查询会很方便,因为如果客户在下午 4 点查询营业时间,我可以找出需要设置的位置例如。
阅读 docs about the operator 我发现您可以提供一组要检查的位置,这将非常适合我的需要。
但这就是问题所在。我无法弄清楚这些职位是如何运作的。
文档状态,位置 0 将位于最低有效位(最右边的位),这意味着如果查询 $bitsAnySet: [0],将找不到存储为营业时间的数字如 254 (0b1111 1110) 的文档:因为在这个例子中最右边的位被设置为 0。
以这种方式使用运算符,在我的测试数据上进行测试我总是运行遇到问题,因为定位似乎不匹配。
所以我给自己写了一个小脚本(在 JavaScript 运行 on NodeJS v12 connecting to MongoDB using Mongoose)只是尝试所有可能的位置:
这是我的脚本:
require ('mongoose').connect ('mongodb://localhost/test', {useCreateIndex: true, useNewUrlParser: true, useFindAndModify: false, useUnifiedTopology: true}).then (() => {
let buffer = Buffer.alloc (6, 0);
// 0xC0 => 0b1100 0000
buffer.writeUInt8 (0xC0, 0);
// 0x07 => 0b0000 0111
buffer.writeUInt8 (0x07, 5);
// buffer should be: 11000000 00000000 00000000 00000000 00000000 00000111
new SomeModel ({data: buffer}).save ().then (model => {
let promises = [];
// just trying out each position
for (let index = 0; index < 48; index ++)
promises.push (SomeModel.findOne ({data: {$bitsAnySet: [index]}}))
Promise.all (promises).then (resolved => {
resolved = resolved.map ((item, index) => {
if (item !== null)
return {index, item: item.data.toString ('hex')};
else return null;
});
// yes, I know it's not very performant to go over the entire array a second time,
// because I could have done it in the first round,
// but this was just some quick and dirty testing :D
resolved = resolved.filter (item => item !== null);
console.log (resolved);
})
}).catch (console.log);
}).catch (console.log);
这是我的小测试脚本,我希望输出如下:
[
{index: 0, item: 'c00000000007'},
{index: 1, item: 'c00000000007'},
{index: 2, item: 'c00000000007'},
{index: 41, item: 'c00000000007'},
{index: 42, item: 'c00000000007'},
]
因为从右边看二进制表示时,它应该首先找到位置 0、1 和 2 的三个,然后它应该在最左端找到最后两个。
但是我得到了这个:
[
{ index: 6, item: 'c00000000007' },
{ index: 7, item: 'c00000000007' },
{ index: 40, item: 'c00000000007' },
{ index: 41, item: 'c00000000007' },
{ index: 42, item: 'c00000000007' }
]
这让我大吃一惊,因为这对我来说是完全出乎意料的。突然开始看起来 MongoDB 是从左边开始的。它在三个之前找到了两个,并且两个位于二进制数据的最左侧。让我感到困惑的是它似乎不是从位置 0 开始的。
如果我没记错的话,我的数据以两个开始,以三个结束。所以 $bitsAnySet: [0] 应该是正确的。
你们有人知道我在这里做错了什么吗?
非常感谢您的帮助!
注意:如果我错了请纠正我,但我相信Promise.all不会改变数组的顺序,这意味着它不能只是是一个承诺在另一个改变其在 'promises' 数组中的位置之前刚刚解决。
注意:该模型没有任何附加字段。它只有默认的 _id 字段和数据字段。
幸运的是我自己解决了这个问题。
这与字节顺序有关。在我看来,我正在考虑大端方式,因此假设它存储如下:
Hex: c0 00 00 00 00 07
Bin: 11000000 00000000 00000000 00000000 00000000 00000111
根据BSON SpecificationBSON是
serialized in little-endian format.
因此它实际上是这样存储的:
Hex: 07 00 00 00 00 C0
Bin: 00000111 00000000 00000000 00000000 00000000 11000000
这解释了为什么索引会混在一起。
我正在做一个小项目,我需要在我的 MongoDB 数据库中存储营业时间。我决定为整个星期使用一个位掩码,由 336 位表示,这意味着每一位代表一天中的 30 分钟。 (使用位掩码没有特殊原因。我愿意改变我存储营业时间的方式,但我很好奇。)
我认为如果我使用 $bitsAnySet 运算符基于位掩码进行查询会很方便,因为如果客户在下午 4 点查询营业时间,我可以找出需要设置的位置例如。
阅读 docs about the operator 我发现您可以提供一组要检查的位置,这将非常适合我的需要。
但这就是问题所在。我无法弄清楚这些职位是如何运作的。 文档状态,位置 0 将位于最低有效位(最右边的位),这意味着如果查询 $bitsAnySet: [0],将找不到存储为营业时间的数字如 254 (0b1111 1110) 的文档:因为在这个例子中最右边的位被设置为 0。
以这种方式使用运算符,在我的测试数据上进行测试我总是运行遇到问题,因为定位似乎不匹配。
所以我给自己写了一个小脚本(在 JavaScript 运行 on NodeJS v12 connecting to MongoDB using Mongoose)只是尝试所有可能的位置:
这是我的脚本:
require ('mongoose').connect ('mongodb://localhost/test', {useCreateIndex: true, useNewUrlParser: true, useFindAndModify: false, useUnifiedTopology: true}).then (() => {
let buffer = Buffer.alloc (6, 0);
// 0xC0 => 0b1100 0000
buffer.writeUInt8 (0xC0, 0);
// 0x07 => 0b0000 0111
buffer.writeUInt8 (0x07, 5);
// buffer should be: 11000000 00000000 00000000 00000000 00000000 00000111
new SomeModel ({data: buffer}).save ().then (model => {
let promises = [];
// just trying out each position
for (let index = 0; index < 48; index ++)
promises.push (SomeModel.findOne ({data: {$bitsAnySet: [index]}}))
Promise.all (promises).then (resolved => {
resolved = resolved.map ((item, index) => {
if (item !== null)
return {index, item: item.data.toString ('hex')};
else return null;
});
// yes, I know it's not very performant to go over the entire array a second time,
// because I could have done it in the first round,
// but this was just some quick and dirty testing :D
resolved = resolved.filter (item => item !== null);
console.log (resolved);
})
}).catch (console.log);
}).catch (console.log);
这是我的小测试脚本,我希望输出如下:
[
{index: 0, item: 'c00000000007'},
{index: 1, item: 'c00000000007'},
{index: 2, item: 'c00000000007'},
{index: 41, item: 'c00000000007'},
{index: 42, item: 'c00000000007'},
]
因为从右边看二进制表示时,它应该首先找到位置 0、1 和 2 的三个,然后它应该在最左端找到最后两个。
但是我得到了这个:
[
{ index: 6, item: 'c00000000007' },
{ index: 7, item: 'c00000000007' },
{ index: 40, item: 'c00000000007' },
{ index: 41, item: 'c00000000007' },
{ index: 42, item: 'c00000000007' }
]
这让我大吃一惊,因为这对我来说是完全出乎意料的。突然开始看起来 MongoDB 是从左边开始的。它在三个之前找到了两个,并且两个位于二进制数据的最左侧。让我感到困惑的是它似乎不是从位置 0 开始的。
如果我没记错的话,我的数据以两个开始,以三个结束。所以 $bitsAnySet: [0] 应该是正确的。
你们有人知道我在这里做错了什么吗? 非常感谢您的帮助!
注意:如果我错了请纠正我,但我相信Promise.all不会改变数组的顺序,这意味着它不能只是是一个承诺在另一个改变其在 'promises' 数组中的位置之前刚刚解决。
注意:该模型没有任何附加字段。它只有默认的 _id 字段和数据字段。
幸运的是我自己解决了这个问题。 这与字节顺序有关。在我看来,我正在考虑大端方式,因此假设它存储如下:
Hex: c0 00 00 00 00 07
Bin: 11000000 00000000 00000000 00000000 00000000 00000111
根据BSON SpecificationBSON是
serialized in little-endian format.
因此它实际上是这样存储的:
Hex: 07 00 00 00 00 C0
Bin: 00000111 00000000 00000000 00000000 00000000 11000000
这解释了为什么索引会混在一起。