記一次Mongodb數據庫查詢之包含所有指定元素的數組或者都在指定元素的數組中


  這里記錄一個查詢需求:數據庫中字段的值(數組類型)都在指定的數組中。舉例說一下實際場景,數據庫中一個字段存儲用戶“可以使用的編程語言”,一般都會是多個,所以該字段是數組格式。現在要查詢的是:會c#、javascript或者只會c#或者只會javascript的用戶,翻譯一下就是數據庫中字段的值是子集而給定的數組是全集。這種查詢需要在mongodb沒有找到特定的查詢操作符,這篇筆記主要解決這個問題,順便介紹一下"$all"運算符。"$all"查詢的是數據庫字段的值包含所有指定元素的數組,也就是數據庫中字段的值是全集而給定的數組是子集,和前面提到的需求相反。

  為了演示上述的兩種查詢需求,先造一些測試數據,下面是表結構:

編程語言調查表(FormId: 507048044944694000, FormVersion: 507048044944694001

唯一標識

中文描述

控件類型

是否必填

表單項的其他配置(在表單設計時配置,文本框長度、時間格式等)

1572493554001

用戶

選擇人員控件

1572493554002

可以使用的編程語言

復選框

1572493554003

最喜歡的編程語言

文本框

1572493554004

工作地點

文本框

1572493554005

工作年限

數值輸入框

1572493554006

備注

多行文本框

  下面是造數據的語句

var GV_TableName = "FormInstace",
    GV_FormId = "507048044944694000",
    GV_FormVersion = "507048044944694001",
    GV_CreateUserIds = ["user10000", "user10001", "user10002", "user10003", "user10004", "user10005", "user10006", "user10007", "user10008", "user10009"];

var GV_LangObj = {
    1: {
        id: "1",
        text: "C#"
    },
    2: {
        id: "2",
        text: "JavaScript"
    },
    3: {
        id: "3",
        text: "HTML"
    },
    4: {
        id: "4",
        text: "CSS"
    },
    5: {
        id: "5",
        text: "Go"
    },
    6: {
        id: "6",
        text: "Rust"
    }
};
var GV_Name2Id = {
    "userName": "1572493554001",
    "lang": "1572493554002",
    "favLang": "1572493554003",
    "workPlace": "1572493554004",
    "workYears": "1572493554005",
    "remarks": "1572493554006",
};

var getGUID = function () {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0,
        v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16).toUpperCase();
    });
}

var getFormInstanceOtherAttrs = function (formId, formVersion) {
    var tempCreateUserIdIndex = Math.floor(Math.random() * GV_CreateUserIds.length),
    tempCreateDate = ISODate();
    return {
        _id: getGUID(),
        ExtendData: {},
        CreateUserId: GV_CreateUserIds[tempCreateUserIdIndex],
        CreateUserName: GV_CreateUserIds[tempCreateUserIdIndex],
        CreateDate: tempCreateDate,
        LastModifyDate: tempCreateDate,
        FormId: GV_FormId,
        FormVersion: GV_FormVersion
    };
};

var assembleFormInstance = function (formItemsAttr) {
    return Object.assign(formItemsAttr, getFormInstanceOtherAttrs());
}

//************************************************************************************************************************************************

//    批量插入數據
db[GV_TableName].insertMany([
        assembleFormInstance({
            FormItems: [{
                    key: GV_Name2Id.userName,
                    value: "u1"
                }, {
                    key: GV_Name2Id.lang,
                    value: [GV_LangObj['1'], GV_LangObj['2'], GV_LangObj['3'], GV_LangObj['4']]
                }, {
                    key: GV_Name2Id.favLang,
                    value: [GV_LangObj['1']]
                }, {
                    key: GV_Name2Id.workPlace,
                    value: "北京"
                }, {
                    key: GV_Name2Id.workYears,
                    value: 1
                }, {
                    key: GV_Name2Id.remarks,
                    value: "隨便寫點什么"
                }
            ]
        }),
        assembleFormInstance({
            FormItems: [{
                    key: GV_Name2Id.userName,
                    value: "u2"
                }, {
                    key: GV_Name2Id.lang,
                    value: [GV_LangObj['1'], GV_LangObj['2'], GV_LangObj['6']]
                }, {
                    key: GV_Name2Id.favLang,
                    value: [GV_LangObj['6']]
                }, {
                    key: GV_Name2Id.workPlace,
                    value: "天津"
                }, {
                    key: GV_Name2Id.workYears,
                    value: 2
                }, {
                    key: GV_Name2Id.remarks,
                    value: "隨便寫點什么"
                }
            ]
        }),
        assembleFormInstance({
            FormItems: [{
                    key: GV_Name2Id.userName,
                    value: "u3"
                }, {
                    key: GV_Name2Id.lang,
                    value: [GV_LangObj['1'], GV_LangObj['2']]
                }, {
                    key: GV_Name2Id.favLang,
                    value: [GV_LangObj['1']]
                }, {
                    key: GV_Name2Id.workPlace,
                    value: "石家庄"
                }, {
                    key: GV_Name2Id.workYears,
                    value: 3
                }, {
                    key: GV_Name2Id.remarks,
                    value: "隨便寫點什么"
                }
            ]
        }),
        assembleFormInstance({
            FormItems: [{
                    key: GV_Name2Id.userName,
                    value: "u4"
                }, {
                    key: GV_Name2Id.lang,
                    value: [GV_LangObj['1'], GV_LangObj['5']]
                }, {
                    key: GV_Name2Id.favLang,
                    value: [GV_LangObj['5']]
                }, {
                    key: GV_Name2Id.workPlace,
                    value: "上海"
                }, {
                    key: GV_Name2Id.workYears,
                    value: 4
                }, {
                    key: GV_Name2Id.remarks,
                    value: "隨便寫點什么"
                }
            ]
        }),
        assembleFormInstance({
            FormItems: [{
                    key: GV_Name2Id.userName,
                    value: "u5"
                }, {
                    key: GV_Name2Id.lang,
                    value: [GV_LangObj['1']]
                }, {
                    key: GV_Name2Id.favLang,
                    value: [GV_LangObj['1']]
                }, {
                    key: GV_Name2Id.workPlace,
                    value: "廣州"
                }, {
                    key: GV_Name2Id.workYears,
                    value: 5
                }, {
                    key: GV_Name2Id.remarks,
                    value: "隨便寫點什么"
                }
            ]
        }),
        assembleFormInstance({
            FormItems: [{
                    key: GV_Name2Id.userName,
                    value: "u6"
                }, {
                    key: GV_Name2Id.lang,
                    value: [GV_LangObj['2']]
                }, {
                    key: GV_Name2Id.favLang,
                    value: [GV_LangObj['2']]
                }, {
                    key: GV_Name2Id.workPlace,
                    value: "深圳"
                }, {
                    key: GV_Name2Id.workYears,
                    value: 6
                }, {
                    key: GV_Name2Id.remarks,
                    value: "隨便寫點什么"
                }
            ]
        }),
        assembleFormInstance({
            FormItems: [{
                    key: GV_Name2Id.userName,
                    value: "u7"
                }, {
                    key: GV_Name2Id.lang,
                    value: []
                }, {
                    key: GV_Name2Id.favLang,
                    value: []
                }, {
                    key: GV_Name2Id.workPlace,
                    value: "成都"
                }, {
                    key: GV_Name2Id.workYears,
                    value: 7
                }, {
                    key: GV_Name2Id.remarks,
                    value: "隨便寫點什么"
                }
            ]
        }),
        assembleFormInstance({
            FormItems: [{
                    key: GV_Name2Id.userName,
                    value: "u8"
                }, {
                    key: GV_Name2Id.lang,
                    value: [GV_LangObj['5'], GV_LangObj['6']]
                }, {
                    key: GV_Name2Id.favLang,
                    value: [GV_LangObj['5']]
                }, {
                    key: GV_Name2Id.workPlace,
                    value: "重慶"
                }, {
                    key: GV_Name2Id.workYears,
                    value: 8
                }, {
                    key: GV_Name2Id.remarks,
                    value: "隨便寫點什么"
                }
            ]
        }),
    ]);
View Code

  看一下插入的數據:

   這里數據結構和之前表單生成器(Form Builder)之表單數據存儲結構mongodb篇文章中介紹的一樣。為了方便查看,將“可以使用的編程語言”字段從“FormItems”數組中拿出來並放在最外層,下面是語句

//    通用聚合管道(將“編程語言”表單項從"FormItems"中拷貝一份放到最外層,方便查看)
var showLangItemPrePipeline = [{
        $addFields: {
            FormItemObj: {
                $arrayToObject: {
                    $map: {
                        input: "$FormItems",
                        as: "field",
                        in: [
                            "$$field.key",
                            "$$field.value"
                        ]
                    }
                }
            }
        }
    }, {
        $addFields: {
            "LangFormItem": "$FormItemObj.1572493554002",
        }
    }, {
        $addFields: {
            "1572493554002": {
                $reduce: {
                    input: "$LangFormItem",
                    initialValue: "",
                    in: {
                        $concat: ["$$value", "$$this.text", ","]
                    }
                }
            },
        }
    }, {
        $project: {
            'FormItemObj': 0,
            'LangFormItem': 0
        }
    }
];
//    1、查詢:展示一下插入的示例數據
db.getCollection("FormInstace").aggregate(showLangItemPrePipeline);

  下面看一下查詢效果:

   說明:從制造假數據的語句中你可以看到“1572493554002”字段是數組類型並且每一項都是一個對象,上圖中將數組拼接成了字符串,方便查看。

  先來看一下數據庫中字段的值都在指定元素的數組中的查詢語句:

//    通用聚合管道(將“編程語言”表單項從"FormItems"中拷貝一份放到最外層,方便查看)
var showLangItemPrePipeline = [{
        $addFields: {
            FormItemObj: {
                $arrayToObject: {
                    $map: {
                        input: "$FormItems",
                        as: "field",
                        in: [
                            "$$field.key",
                            "$$field.value"
                        ]
                    }
                }
            }
        }
    }, {
        $addFields: {
            "LangFormItem": "$FormItemObj.1572493554002",
        }
    }, {
        $addFields: {
            "1572493554002": {
                $reduce: {
                    input: "$LangFormItem",
                    initialValue: "",
                    in: {
                        $concat: ["$$value", "$$this.text", ","]
                    }
                }
            },
        }
    }, {
        $project: {
            'FormItemObj': 0,
            'LangFormItem': 0
        }
    }
];
db.getCollection("FormInstace").aggregate(showLangItemPrePipeline.concat([{
                "$match": {
                    "FormId": "507048044944694000",
                    "FormItems": {
                        "$elemMatch": {
                            "key": "1572493554002",
                            "value.0": {
                                '$exists': true
                            },
                            "value": {
                                "$not": {
                                    "$elemMatch": {
                                        "text": {
                                            "$nin": ["C#", "JavaScript"]
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        ]))

  來一張截圖,看一下查詢結果:

   注意:這里語句中還用到了“$exists”運算符,如果不添加這個會將數組長度為0的查出來。參考鏈接

  在看一下“$all”查詢,數據庫字段的值包含所有指定元素的數組:

//    通用聚合管道(將“編程語言”表單項從"FormItems"中拷貝一份放到最外層,方便查看)
var showLangItemPrePipeline = [{
        $addFields: {
            FormItemObj: {
                $arrayToObject: {
                    $map: {
                        input: "$FormItems",
                        as: "field",
                        in: [
                            "$$field.key",
                            "$$field.value"
                        ]
                    }
                }
            }
        }
    }, {
        $addFields: {
            "LangFormItem": "$FormItemObj.1572493554002",
        }
    }, {
        $addFields: {
            "1572493554002": {
                $reduce: {
                    input: "$LangFormItem",
                    initialValue: "",
                    in: {
                        $concat: ["$$value", "$$this.text", ","]
                    }
                }
            },
        }
    }, {
        $project: {
            'FormItemObj': 0,
            'LangFormItem': 0
        }
    }
];
db.getCollection('FormInstace').aggregate(showLangItemPrePipeline.concat([{
                "$match": {
                    "FormId": "507048044944694000",
                    "FormItems": {
                        "$elemMatch": {
                            "key": "1572493554002",
                            "value.text": {
                                "$all": ["C#", "JavaScript"]
                            }
                        }
                    }
                }
            }
        ]))

  來一張截圖,看一下查詢結果:

   這里在順便記錄一下在mongodb中數值轉字符串,高版本有“$toString”操作符(版本4.0)、“$convert”操作符(版本4.0)……但是低版本的該如何處理,參考鏈接。這個例子比較簡單,就不寫制造數據的語句了,直接來查詢語句:

db.getCollection('test001').aggregate([
    {
        $addFields: {
            "ageStr": { $substr: [ "$num", 0, -1 ] }
        }
    }
])

  來一張截圖,看一下查詢結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM