草庐IT

mongodb自定义比较到filter

coder 2023-10-27 原文

我的数据如下:

{max:3.4.6, min: 1.10.2}
{max:10.9.12, min:6.90.1}

号码3.5.6存储为 string , 和 0.10.0应该大于 0.9.0 .我想再给一个号码cur , 并返回 cur 之间的所有结果。

find all document where min < cur < max

我可以定义一个可以识别1.10.2 < 2.1.3 < 3.4.6的比较函数吗? ?并用它来做查询?

最佳答案

还有一个聚合框架解决方案可供您使用,但它需要当前版本的 mongoDB,因为它使用 $split$strLenBytes 运算符。我在 3.3.10 版上创建了它。

这个想法基本上是基于用前导零填充你的版本部分直到固定大小(在我的例子中每个部分可以从 000 到 999 但你可以根据需要调整它)并对文档字段做同样的事情minmax 以便比较字符串。
所以对于这样的样本数据

/* 1 */
{
    "_id" : ObjectId("57ac0c264ae6fbd5fb5b6e97"),
    "max" : "3.4.6",
    "min" : "1.10.2"
}

/* 2 */
{
    "_id" : ObjectId("57ac0c264ae6fbd5fb5b6e98"),
    "max" : "10.9.12",
    "min" : "6.90.1"
}

/* 3 */
{
    "_id" : ObjectId("57ac0c264ae6fbd5fb5b6e99"),
    "max" : "3.5.9",
    "min" : "0.5.7"
}

/* 4 */
{
    "_id" : ObjectId("57ac0c264ae6fbd5fb5b6e9a"),
    "max" : "2.0.0",
    "min" : "1.5.0"
}

管道

var cur = "1.11.1";
var curParts = cur.split('.');
var curPadded = ("00" + curParts[0]).slice(-3) + "." +
                ("00" + curParts[1]).slice(-3) + "." +
                ("00" + curParts[2]).slice(-3);

db.getCollection('minmax').aggregate([
    {
        $project: {
            min: 1, max: 1,
            maxTmp: {
                $let: {
                    vars: {
                        maxParts: { $split: ["$max", "."] }
                    },
                    in: {
                       major: { $arrayElemAt: ["$$maxParts", 0] },
                       majorLen: { $strLenBytes: { $arrayElemAt: ["$$maxParts", 0] } },
                       minor: { $arrayElemAt: ["$$maxParts", 1] },
                       minorLen: { $strLenBytes: { $arrayElemAt: ["$$maxParts", 1] } },
                       patch: { $arrayElemAt: ["$$maxParts", 2] },
                       patchLen: { $strLenBytes: { $arrayElemAt: ["$$maxParts", 2] } }
                    }
                }
            },
            minTmp: {
                $let: {
                    vars: {
                        minParts: { $split: ["$min", "."] }
                    },
                    in: {
                       major: { $arrayElemAt: ["$$minParts", 0] },
                       majorLen: { $strLenBytes: { $arrayElemAt: ["$$minParts", 0] } },
                       minor: { $arrayElemAt: ["$$minParts", 1] },
                       minorLen: { $strLenBytes: { $arrayElemAt: ["$$minParts", 1] } },
                       patch: { $arrayElemAt: ["$$minParts", 2] },
                       patchLen: { $strLenBytes: { $arrayElemAt: ["$$minParts", 2] } }
                    }
                }
            }            
        }
    },
    {
        $project: {
            min: 1, max: 1,
            maxMajor: { $substr: [{ $concat: ["_00", "$maxTmp.major"] }, "$maxTmp.majorLen", 3] },
            maxMinor: { $substr: [{ $concat: ["_00", "$maxTmp.minor"] }, "$maxTmp.minorLen", 3] },
            maxPatch: { $substr: [{ $concat: ["_00", "$maxTmp.patch"] }, "$maxTmp.patchLen", 3] },
            minMajor: { $substr: [{ $concat: ["_00", "$minTmp.major"] }, "$minTmp.majorLen", 3] },
            minMinor: { $substr: [{ $concat: ["_00", "$minTmp.minor"] }, "$minTmp.minorLen", 3] },
            minPatch: { $substr: [{ $concat: ["_00", "$minTmp.patch"] }, "$minTmp.patchLen", 3] },            
        }
    },
    {
        $project: {
            min: 1, max: 1,
            maxPadded: { $concat: ["$maxMajor", ".", "$maxMinor", ".", "$maxPatch"] },
            minPadded: { $concat: ["$minMajor", ".", "$minMinor", ".", "$minPatch"] }
        }
    },
    {
        $match: {
            maxPadded: { $gt: curPadded },
            minPadded: { $lt: curPadded }
        }
    },
    {
        $project: {
           min: 1,
           max: 1
        }
    }
])  

将产生输出

/* 1 */
{
    "_id" : ObjectId("57ac0c264ae6fbd5fb5b6e97"),
    "max" : "3.4.6",
    "min" : "1.10.2"
}

/* 2 */
{
    "_id" : ObjectId("57ac0c264ae6fbd5fb5b6e99"),
    "max" : "3.5.9",
    "min" : "0.5.7"
}

/* 3 */
{
    "_id" : ObjectId("57ac0c264ae6fbd5fb5b6e9a"),
    "max" : "2.0.0",
    "min" : "1.5.0"
}

解释

第一阶段用“.”分割字符串的各个部分并确定这些字符串的长度,以便可以在下一阶段将字符串修剪为固定大小。

$project: {
    min: 1, max: 1,
    maxTmp: {
        $let: {
            vars: {
                maxParts: { $split: ["$max", "."] }
            },
            in: {
                major: { $arrayElemAt: ["$$maxParts", 0] },
                majorLen: { $strLenBytes: { $arrayElemAt: ["$$maxParts", 0] } },
                minor: { $arrayElemAt: ["$$maxParts", 1] },
                minorLen: { $strLenBytes: { $arrayElemAt: ["$$maxParts", 1] } },
                patch: { $arrayElemAt: ["$$maxParts", 2] },
                patchLen: { $strLenBytes: { $arrayElemAt: ["$$maxParts", 2] } }
            }
        }
    },
    minTmp: ... // same idea
}

管道中的文档现在看起来像这样

/* 1 */
{
    "_id" : ObjectId("57ac0c264ae6fbd5fb5b6e97"),
    "max" : "3.4.6",
    "min" : "1.10.2",
    "maxTmp" : {
        "major" : "3",
        "majorLen" : 1,
        "minor" : "4",
        "minorLen" : 1,
        "patch" : "6",
        "patchLen" : 1
    }
}
... // others

如前所述,现在必须将各个部分填充并修剪到固定大小

$project: {
    min: 1, max: 1,
    maxMajor: { $substr: [{ $concat: ["_00", "$maxTmp.major"] }, "$maxTmp.majorLen", 3] },
    maxMinor: { $substr: [{ $concat: ["_00", "$maxTmp.minor"] }, "$maxTmp.minorLen", 3] },
    maxPatch: { $substr: [{ $concat: ["_00", "$maxTmp.patch"] }, "$maxTmp.patchLen", 3] },
    minMajor: ... // same idea
}  

所以文档现在看起来像这样

/* 1 */
{
    "_id" : ObjectId("57ac0c264ae6fbd5fb5b6e97"),
    "max" : "3.4.6",
    "min" : "1.10.2",
    "maxMajor" : "003",
    "maxMinor" : "004",
    "maxPatch" : "006",
    "minMajor" : "001",
    "minMinor" : "010",
    "minPatch" : "002"
}
... // others  

在将它们与您的过滤器进行匹配之前,必须通过

将它们连接起来
$project: {
    min: 1, max: 1,
    maxPadded: { $concat: ["$maxMajor", ".", "$maxMinor", ".", "$maxPatch"] },
    minPadded: ... // same idea
}

产生

/* 1 */
{
    "_id" : ObjectId("57ac0c264ae6fbd5fb5b6e97"),
    "max" : "3.4.6",
    "min" : "1.10.2",
    "maxPadded" : "003.004.006",
    "minPadded" : "001.010.002"
}
... // others  

最后两个阶段进行实际匹配并将文档 reshape 为原始状态

$match: {
    maxPadded: { $gt: curPadded },
    minPadded: { $lt: curPadded }
},
$project: {
    min: 1,
    max: 1
}

最后说明:通过将 $project 阶段“压缩”为一个阶段,管道可能会更短,但我想这真的很难跟进,因此我拆分了 $project 分为几个阶段。

关于mongodb自定义比较到filter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38887310/

有关mongodb自定义比较到filter的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  3. ruby - Ruby 的 Hash 在比较键时使用哪种相等性测试? - 2

    我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。

  4. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  5. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  6. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  7. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  8. ruby - 如何在 Grape 中定义哈希数组? - 2

    我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>

  9. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  10. ruby - 这两个 Ruby 类初始化定义有什么区别? - 2

    我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是

随机推荐