MongoDB UUID、Base64、CSUUID 转换工具

<div class="form-group"><label for="base64" class="TransformTitle">Base64 :</label> <input type="text" id="base64" class="TransformButton" placeholder="请输入 Base64" /><button id="btnBase64" class="btn btn-primary">转换</button><div class="TransformResult"></div></div>
<div class="form-group"><label for="uuid" class="TransformTitle">UUID :</label> <input type="text" id="uuid" class="TransformButton" placeholder="请输入 UUID" /><button id="btnUuid" class="btn btn-primary">转换</button><div class="TransformResult"></div></div>
<div class="form-group"><label for="juuid" class="TransformTitle">JUUID :</label> <input type="text" id="juuid" class="TransformButton" placeholder="请输入 JUUID" /><button id="btnJuuid" class="btn btn-primary">转换</button><div class="TransformResult"></div></div>
<div class="form-group"><label for="csuuid" class="TransformTitle">CSUUID :</label> <input type="text" id="csuuid" class="TransformButton" placeholder="请输入 CSUUID" /><button id="btnCsuuid" class="btn btn-primary">转换</button><div class="TransformResult"></div></div>
<div class="form-group"><label for="pyuuid" class="TransformTitle">PYUUID :</label> <input type="text" id="pyuuid" class="TransformButton" placeholder="请输入 PYUUID" /><button id="btnPyuuid" class="btn btn-primary">转换</button><div class="TransformResult"></div></div>

<style>
    label.TransformTitle {
        width: 100px;
    }
    input.TransformButton {
        min-width: 300px;
        margin: 0px 10px;
    }
    label.TransformTitle {
        font-weight: bold;
    }
    .TransformResult {
        display: none;
        margin-left: 20px;
    }
    .TransformResult .TransformTo {
        font-style: italic;
    }
    .TransformResult .Type {
        color: #257fad;
    }
    .TransformResult .Str {
        color: #568c3b;
    }
    .TransformResultRow {
        display: block;
    }
</style>

<script>
    $(function() {
        $("#btnBase64").click(function() {
            let val = $("#base64").val();
            var divResult = $($(this).parent()).find(".TransformResult");
            divResult.html(TransformResultHtml(
                { Type: "Base64", Value: toBase64(val) },
                { Type: "UUID", Value: toUUID(val) },
                { Type: "JUUID", Value: toJUUID(val) },
                { Type: "CSUUID", Value: toCSUUID(val) },
                { Type: "PYUUID", Value: toPYUUID(val) }
            )).show();
        });
    });
    $(function() {
        $("#btnUuid").click(function() {
            let val = UUID($("#uuid").val());
            var divResult = $($(this).parent()).find(".TransformResult");
            divResult.html(TransformResultHtml(
                { Type: "Base64", Value: toBase64(val) },
                { Type: "UUID", Value: toUUID(val) },
                { Type: "JUUID", Value: toJUUID(val) },
                { Type: "CSUUID", Value: toCSUUID(val) },
                { Type: "PYUUID", Value: toPYUUID(val) },
                { Type: "HexUUID", Value: toHexUUID(4, val) }
            )).show();
        });
    });
    $(function() {
        $("#btnJuuid").click(function() {
            let val = JUUID($("#juuid").val());
            var divResult = $($(this).parent()).find(".TransformResult");
            divResult.html(TransformResultHtml(
                { Type: "Base64", Value: toBase64(val) },
                { Type: "UUID", Value: toUUID(val) },
                { Type: "JUUID", Value: toJUUID(val) },
                { Type: "CSUUID", Value: toCSUUID(val) },
                { Type: "PYUUID", Value: toPYUUID(val) },
                { Type: "HexUUID", Value: toHexUUID(3, val) }
            )).show();
        });
    });
    $(function() {
        $("#btnCsuuid").click(function() {
            let val = CSUUID($("#csuuid").val());
            var divResult = $($(this).parent()).find(".TransformResult");
            divResult.html(TransformResultHtml(
                { Type: "Base64", Value: toBase64(val) },
                { Type: "UUID", Value: toUUID(val) },
                { Type: "JUUID", Value: toJUUID(val) },
                { Type: "CSUUID", Value: toCSUUID(val) },
                { Type: "PYUUID", Value: toPYUUID(val) },
                { Type: "HexUUID", Value: toHexUUID(3, val) }
            )).show();
        });
    });
    $(function() {
        $("#btnPyuuid").click(function() {
            let val = PYUUID($("#pyuuid").val());
            var divResult = $($(this).parent()).find(".TransformResult");
            divResult.html(TransformResultHtml(
                { Type: "Base64", Value: toBase64(val) },
                { Type: "UUID", Value: toUUID(val) },
                { Type: "JUUID", Value: toJUUID(val) },
                { Type: "CSUUID", Value: toCSUUID(val) },
                { Type: "PYUUID", Value: toPYUUID(val) },
                { Type: "HexUUID", Value: toHexUUID(3, val) }
            )).show();
        });
    });
    function TransformResultHtml(...results) {
        let resultHtml = "";
        for(let result of results) {
            console.log(result);
             resultHtml = resultHtml + "<div class=\"TransformResultRow\"><span class=\"TransformTo\">to</span> <code>" + result.Type + "</code> : <span class=\"TransformToResult\">" + result.Value + "</span></div>";
        }
        console.log(resultHtml);
        return resultHtml;
    }
    function HexToBase64(hex) {
        var base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        var base64 = "";
        var group;
        for (var i = 0; i < 30; i += 6) {
            group = parseInt(hex.substr(i, 6), 16);
            base64 += base64Digits[(group >> 18) & 0x3f];
            base64 += base64Digits[(group >> 12) & 0x3f];
            base64 += base64Digits[(group >> 6) & 0x3f];
            base64 += base64Digits[group & 0x3f];
        }
        group = parseInt(hex.substr(30, 2), 16);
        base64 += base64Digits[(group >> 2) & 0x3f];
        base64 += base64Digits[(group << 4) & 0x3f];
        base64 += "==";
        return base64;
    }
    function Base64ToHex(base64) {
        var base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        var hexDigits = "0123456789abcdef";
        var hex = "";
        for (var i = 0; i < 24;) {
            var e1 = base64Digits.indexOf(base64[i++]);
            var e2 = base64Digits.indexOf(base64[i++]);
            var e3 = base64Digits.indexOf(base64[i++]);
            var e4 = base64Digits.indexOf(base64[i++]);
            var c1 = (e1 << 2) | (e2 >> 4);
            var c2 = ((e2 & 15) << 4) | (e3 >> 2);
            var c3 = ((e3 & 3) << 6) | e4;
            hex += hexDigits[c1 >> 4];
            hex += hexDigits[c1 & 15];
            if (e3 != 64) {
                hex += hexDigits[c2 >> 4];
                hex += hexDigits[c2 & 15];
            }
            if (e4 != 64) {
                hex += hexDigits[c3 >> 4];
                hex += hexDigits[c3 & 15];
            }
        }
        return hex;
    }
    function UUID(uuid) {
        var hex = uuid.replace(/[{}-]/g, ""); // remove extra characters
        var base64 = HexToBase64(hex);
        return base64; // new subtype 4
    }
    function JUUID(uuid) {
        var hex = uuid.replace(/[{}-]/g, ""); // remove extra characters
        var msb = hex.substr(0, 16);
        var lsb = hex.substr(16, 16);
        msb = msb.substr(14, 2) + msb.substr(12, 2) + msb.substr(10, 2) + msb.substr(8, 2) + msb.substr(6, 2) + msb.substr(4, 2) + msb.substr(2, 2) + msb.substr(0, 2);
        lsb = lsb.substr(14, 2) + lsb.substr(12, 2) + lsb.substr(10, 2) + lsb.substr(8, 2) + lsb.substr(6, 2) + lsb.substr(4, 2) + lsb.substr(2, 2) + lsb.substr(0, 2);
        hex = msb + lsb;
        var base64 = HexToBase64(hex);
        return base64;
    }
    function CSUUID(uuid) {
        var hex = uuid.replace(/[{}-]/g, ""); // remove extra characters
        var a = hex.substr(6, 2) + hex.substr(4, 2) + hex.substr(2, 2) + hex.substr(0, 2);
        var b = hex.substr(10, 2) + hex.substr(8, 2);
        var c = hex.substr(14, 2) + hex.substr(12, 2);
        var d = hex.substr(16, 16);
        hex = a + b + c + d;
        var base64 = HexToBase64(hex);
        return base64;
    }
    function PYUUID(uuid) {
        var hex = uuid.replace(/[{}-]/g, ""); // remove extra characters
        var base64 = HexToBase64(hex);
        return base64;
    }
    function toBase64(base64) {
        return '<span class="Str">' + base64 + '</span>';
    }
    function toUUID(base64) {
        var hex = Base64ToHex(base64); // don't use BinData's hex function because it has bugs in older versions of the shell
        var uuid = hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12);
        return '<span class="Type">UUID</span>(<span class="Str">\'' + uuid + '\'</span>)';
    }
    function toJUUID(base64) {
        var hex = Base64ToHex(base64); // don't use BinData's hex function because it has bugs in older versions of the shell
        var msb = hex.substr(0, 16);
        var lsb = hex.substr(16, 16);
        msb = msb.substr(14, 2) + msb.substr(12, 2) + msb.substr(10, 2) + msb.substr(8, 2) + msb.substr(6, 2) + msb.substr(4, 2) + msb.substr(2, 2) + msb.substr(0, 2);
        lsb = lsb.substr(14, 2) + lsb.substr(12, 2) + lsb.substr(10, 2) + lsb.substr(8, 2) + lsb.substr(6, 2) + lsb.substr(4, 2) + lsb.substr(2, 2) + lsb.substr(0, 2);
        hex = msb + lsb;
        var uuid = hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12);
        return '<span class="Type">JUUID</span>(<span class="Str">\'' + uuid + '\'</span>)';
    }
    function toCSUUID(base64) {
        var hex = Base64ToHex(base64); // don't use BinData's hex function because it has bugs in older versions of the shell
        var a = hex.substr(6, 2) + hex.substr(4, 2) + hex.substr(2, 2) + hex.substr(0, 2);
        var b = hex.substr(10, 2) + hex.substr(8, 2);
        var c = hex.substr(14, 2) + hex.substr(12, 2);
        var d = hex.substr(16, 16);
        hex = a + b + c + d;
        var uuid = hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12);
        return '<span class="Type">CSUUID</span>(<span class="Str">"' + uuid + '"</span>)';;
    }
    function toPYUUID(base64) {
        var hex = Base64ToHex(base64); // don't use BinData's hex function because it has bugs
        var uuid = hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12);
        return '<span class="Type">PYUUID</span>(<span class="Str">\'' + uuid + '\'</span>)';
    }
    function toHexUUID(subtype, base64) {
        var hex = Base64ToHex(base64); // don't use BinData's hex function because it has bugs
        var uuid = hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12);
        return '<span class="Type">HexData</span>(' + subtype + ', <span class="Str">\'' + uuid + '\'</span>)';
    }
</script>
MongoDB 分片(sharding)

按值的范围进行横向分片,简称分片(sharding)

创建两个 mongo 服务器并分别启动;

cd /mongodb/
mkdir ./mongo4 ./mongo5

cd /mongodb/
./bin/mongod --shardsvr --dbpath ./mongo4 --port 27014

cd /mongodb/
./bin/mongod --shardsvr --dbpath ./mongo5 --port 27015
MongoDB 副本集

创建三个目录用于存放数据。

cd /mongodb/
mkdir ./mongo1 ./mongo2 ./mongo3

打开三个控制台,分别启动一个 mongo 服务器。

cd /mongodb/
./bin/mongod --replSet book --dbpath ./mongo1 --port 27011 --rest

cd /mongodb/
./bin/mongod --replSet book --dbpath ./mongo2 --port 27012 --rest

cd /mongodb/
./bin/mongod --replSet book --dbpath ./mongo3 --port 27013 --rest
MongoDB mapreduce

实现功能

生成一份报表,对每个国家中,包含同样数字的电话号码进行计数。

实现方法

  • 首先,创建一个辅助函数。它抽取所有不同的数字,构成一个数组。

    点击查看代码
    > distinctDigits = function(phone) {
    ...         var 
    ...                 number = phone.components.number + '',
    ...                 seen = ,
    ...                 result = ,
    ...                 i = number.length;
    ...         while(i--) {
    ...                 seen[+number] = 1;
    ...         }
    ...         for(i=0; i<10; i++) {
    ...                 if (seen[i]) {
    ...                         result[result.length] = i;
    ...                 }
    ...         }
    ...         return result;
    ... }
    function (phone) {
            var 
                    number = phone.components.number + '',
                    seen = ,
                    result = ,
                    i = number.length;
            while(i--) {
                    seen[+number[i]] = 1;
            }
            for(i=0; i<10; i++) {
                    if (seen[i]) {
                            result[result.length] = i;
                    }
            }
            return result;
    }
    > db.system.js.save({_id : 'distinctDigits', value: distinctDigits})
    WriteResult({
            "nMatched" : 0,
            "nUpserted" : 1,
            "nModified" : 0,
            "_id" : "distinctDigits"
    })
    > db.eval("distinctDigits(db.phones.findOne({ 'components.number': 5551213 }))")
    WARNING: db.eval is deprecated
    [ 1, 2, 3, 5 ]
    
  • 其次,准备 mapreduce 函数

    点击查看代码
    > map = function() {
    ...         var digits = distinctDigits(this);
    ...         emit({ digits : digits, country : this.components.country }, { count : 1 });
    ... }
    function () {
            var digits = distinctDigits(this);
            emit({ digits : digits, country : this.components.country }, { count : 1 });
    }
    > reduce = function(key, values) {
    ...         var total = 0;
    ...         for(var i=0; i<values.length; i++) {
    ...                 total += values[i].count;
    ...         }
    ...         return {count : total };
    ... }
    function (key, values) {
            var total = 0;
            for(var i=0; i<values.length; i++) {
                    total += values[i].count;
            }
            return {count : total };
    }
    
  • 最后,执行 mapreduce 操作

    点击查看代码
    > results = db.runCommand({
    ...         mapReduce: 'phones',
    ...         map: map,
    ...         reduce: reduce,
    ...         out: 'phones.report'
    ... });
    {
            "result" : "phones.report",
            "timeMillis" : 9690,
            "counts" : {
                    "input" : 316229,
                    "emit" : 316229,
                    "reduce" : 76620,
                    "output" : 3491
            },
            "ok" : 1
    }
    
  • 因为通过 out 参数设置了集合的名称( out: 'phones.report' ),所以可以像其它集合那样查询结果。

    点击查看查询结果
    > db.phones.report.find({'_id.country' : 8})
    { "_id" : { "digits" : [ 0, 1, 2, 3, 4, 5, 6 ], "country" : 8 }, "value" : { "count" : 46 } }
    { "_id" : { "digits" : [ 0, 1, 2, 3, 5 ], "country" : 8 }, "value" : { "count" : 5 } }
    { "_id" : { "digits" : [ 0, 1, 2, 3, 5, 6 ], "country" : 8 }, "value" : { "count" : 170 } }
    { "_id" : { "digits" : [ 0, 1, 2, 3, 5, 6, 7 ], "country" : 8 }, "value" : { "count" : 36 } }
    { "_id" : { "digits" : [ 0, 1, 2, 3, 5, 6, 8 ], "country" : 8 }, "value" : { "count" : 33 } }
    { "_id" : { "digits" : [ 0, 1, 2, 3, 5, 6, 9 ], "country" : 8 }, "value" : { "count" : 33 } }
    { "_id" : { "digits" : [ 0, 1, 2, 3, 5, 7 ], "country" : 8 }, "value" : { "count" : 8 } }
    { "_id" : { "digits" : [ 0, 1, 2, 3, 5, 8 ], "country" : 8 }, "value" : { "count" : 5 } }
    { "_id" : { "digits" : [ 0, 1, 2, 3, 5, 9 ], "country" : 8 }, "value" : { "count" : 13 } }
    { "_id" : { "digits" : [ 0, 1, 2, 4, 5 ], "country" : 8 }, "value" : { "count" : 12 } }
    { "_id" : { "digits" : [ 0, 1, 2, 4, 5, 6 ], "country" : 8 }, "value" : { "count" : 162 } }
    { "_id" : { "digits" : [ 0, 1, 2, 4, 5, 6, 7 ], "country" : 8 }, "value" : { "count" : 31 } }
    { "_id" : { "digits" : [ 0, 1, 2, 4, 5, 6, 8 ], "country" : 8 }, "value" : { "count" : 28 } }
    { "_id" : { "digits" : [ 0, 1, 2, 4, 5, 6, 9 ], "country" : 8 }, "value" : { "count" : 38 } }
    { "_id" : { "digits" : [ 0, 1, 2, 4, 5, 7 ], "country" : 8 }, "value" : { "count" : 5 } }
    { "_id" : { "digits" : [ 0, 1, 2, 4, 5, 8 ], "country" : 8 }, "value" : { "count" : 8 } }
    { "_id" : { "digits" : [ 0, 1, 2, 4, 5, 9 ], "country" : 8 }, "value" : { "count" : 10 } }
    { "_id" : { "digits" : [ 0, 1, 2, 5 ], "country" : 8 }, "value" : { "count" : 24 } }
    { "_id" : { "digits" : [ 0, 1, 2, 5, 6 ], "country" : 8 }, "value" : { "count" : 264 } }
    { "_id" : { "digits" : [ 0, 1, 2, 5, 6, 7 ], "country" : 8 }, "value" : { "count" : 139 } }
    Type "it" for more
    

    输入 it 可以继续遍历结果集。

MongoDB 聚合函数

  1. count() 查询并返回匹配文档的个数

    > db.phones.count()
    316229
    > db.phones.count({'components.number': {$gt: 5599999}})
    172471
    
  2. distinct() 返回每个匹配的值(不是整个文档)

    > db.phones.distinct('components.number', {'components.number': {$lt: 5550005}})
    
  3. group() 类似于 SQL 中的 GROUP BY

    > db.phones.group({
    ... initial:{count: 0 },
    ... reduce:function(phone, output) { output.count++; },
    ... cond: {'components.number': {$gt: 5599999}},
    ... key: {'components.area' : true}
    ... })
    

    下面两个例子用来展示 group 函数的灵活性。

    • 3.1. 使用 group() 调用来重现 count() 函数的结果

      > db.phones.group({
          ... initial:{count: 0 },
          ... reduce:function(phone, output) { output.count++; },
          ... cond: {'components.number': {$gt: 5599999}}
          ... })
      
          > db.phones.count({'components.number': {$gt: 5599999}})
          172471
          ```
      
      
    • 3.2. 使用 group() 调用来重现 distinct() 函数的结果

      > db.phones.group({
      ... initial: { prefixes: {} },
      ... reduce: function(phone, output) {
      ... output.prefixes = 1;
      ... },
      ... finalize: function (out) {
      ... var ary = ;
      ... for(var p in out.prefixes) { ary.push(parseInt(p)); }
      ... out.prefixes = ary;
      ... }
      ... }).prefixes
      
      > db.phones.distinct('components.prefix')
      
MongoDB 创建索引以提高查询效率

db.phones 中有 11w 条记录,通过 explain 方法解析查询语句:

db.phones.find({display: "+1 800-5550010"}).explain("executionStats") 
MongoDB 常用命令

1. 创建 DB

// 创建名为book的新数据库
mongo book

2. 创建一个集合

// 只要在该集合中插入第一条记录,即会自动创建该集合
db.towns.insert({
    name:"New York",
    population: 22200000,
    last_census:ISODate("2009-07-31"),
    famous_for: ["status of liberty", "food"],
    mayor_info: {
        name: "Michael Bloomberg",
        party: "I"
    }
});
MongoDB 加载自定义的 JS 脚本

  1. 创建 js 脚本 ( insert_city.js ),内容如下:

    function insertCity(name, population, last_census, famous_for, mayor_info)
    {
        db.towns.insert({
        name:name,
        population:population,
        last_census:ISODate(last_census),
        famous_for:famous_for,
        mayor_info:mayor_info
        });
    }
    
  2. 使用 load 命令加载 js 文件 (需要对该目录有读权限)

    load("/mongodb/scripts/insert_city.js")
    
  3. 之后可以使用该方法 Insert 数据

    insertCity("Punxsutawney", 6200, '2008-31-01', , {name:"Jim Wehrle"})
    insertCity("Portland", 582000, '2007-20-09', , {name:"Sam Adams", party: "D" })