<dfn id="hx5t3"><strike id="hx5t3"><em id="hx5t3"></em></strike></dfn>

    <thead id="hx5t3"></thead><nobr id="hx5t3"><font id="hx5t3"><rp id="hx5t3"></rp></font></nobr>

    <listing id="hx5t3"></listing>

    <var id="hx5t3"></var>
    <big id="hx5t3"></big>

      
      

      <output id="hx5t3"><ruby id="hx5t3"></ruby></output>
      <menuitem id="hx5t3"><dfn id="hx5t3"></dfn></menuitem>

      <big id="hx5t3"></big>

        旅圖灬

        旅圖灬 查看完整檔案

        北京編輯聊城大學  |  軟件工程 編輯好未來  |  前端 編輯 xwlyc.github.io/ 編輯
        編輯

        任何事物都有它的正反面,研究技術要全面

        個人動態

        旅圖灬 贊了文章 · 4月7日

        Sequelize學習經驗(ORM框架)

        什么是ORM?

        簡單的講就是對SQL查詢語句的封裝,讓我們可以用OOP的方式操作數據庫,優雅的生成安全、可維護的SQL代碼。直觀上,是一種Model和SQL的映射關系。

        模型常用類型定義


        BOOLEAN  布爾類型
        STRING 字符串類型,類似varchar
        CHAR 定長字符串
        TEXT 文本類型
        INTEGER 整數類型
        FLOAT
        DOUBLE
        DECIMAL
        DATE
        ENUM 枚舉類型
        NOW 當前時間戳
        UUID UUID類型列,其默認值可以為UUIDV1或UUIDV4
        UUIDV1  v1:是基于時間的uuid,通過計算當前時間戳、隨機數和機器MAC地址得到。
        UUIDV2  v4:根據隨機數,或者偽隨機數生成UUID
          uuid.v4().replace(/\-/g, '') //去除‘-’
        

        更多看官方文檔說明,或者這個老哥的博客

        模型字段驗證


        id: {
                type: Sequelize.UUIDV4,
                primaryKey: true, // 主鍵
                allowNull: false,   //不為空
                // autoIncrement: true, //自增
                unique: true,
                defaultValue: NOW, //默認值的設置
                comment:'', // 說明
                validate: {
                    is: ["^[a-z]+$",'i'],     // 只允許字母
                    is: /^[a-z]+$/i,          // 只允許字母
                    not: ["[a-z]",'i'],       // 不能使用字母
                    isEmail: true,            // 檢測郵箱格式 (foo@bar.com)
                    isUrl: true,              // 檢查Url格式 (http://foo.com)
                    isIP: true,               // 檢查 IPv4 或 IPv6 格式
                    isIPv4: true,             // 檢查 IPv4
                    isIPv6: true,             // 檢查 IPv6
                    isAlpha: true,            // 不能使用字母
                    isAlphanumeric: true,     // 只允許字母數字字符
                    isNumeric: true,          // 只能使用數字
                    isInt: true,              // 只能是整數
                    isFloat: true,            // 只能是浮點數
                    isDecimal: true,          // 檢查數字
                    isLowercase: true,        // 檢查小寫字母
                    isUppercase: true,        // 檢查大寫字母
                    notNull: true,            // 不允許null
                    isNull: true,             // 只能為null
                    notEmpty: true,           // 不能空字符串
                    equals: 'specific value', // 只能使用指定值
                    contains: 'foo',          // 必須包含子字符串
                    notIn: [['foo', 'bar']],  // 不能是數組中的任意一個值
                    isIn: [['foo', 'bar']],   // 只能是數組中的任意一個值
                    notContains: 'bar',       // 不能包含子字符串
                    len: [2, 10],              // 值的長度必在 2 和 10 之間
                    isUUID: 4,                // 只能是UUID
                    isDate: true,             // 只能是日期字符串
                    isAfter: "2011-11-05",    // 只能使用指定日期之后的時間
                    isBefore: "2011-11-05",   // 只能使用指定日期之前的時間
                    max: 23,                  // 允許的最大值
                    min: 23,                  // 允許的最小值
                    isArray: true,            // 不能使用數組
                    isCreditCard: true,       // 檢查是有效的信用卡
        
                    // 也可以自定義驗證:
                    isEven: function(value) {
                        if(parseInt(value) % 2 != 0) {
                        throw new Error('Only even values are allowed!')
                        // we also are in the model's context here, so this.otherField
                        // would get the value of otherField if it existed
                        }
                    }
                },
                // 假設昵稱后要加上 id 值
                get() {
                    const id = this.getDataValue('id');
                    return this.getDataValue('nickName') + '-' + id;
                },
                // set 假設數據庫中存儲的郵箱都要是大寫的,可以在此處改寫
                set(val) {
                    this.setDataValue('email', val.toUpperCase());
                },
            },

        詳情看官方文檔

        模型使用

        查詢

        • findById

        await Role.findById(1);

        • findByPk
        await Role.findByPk(123)
        • findOne
        await Role.findOne({
                where: {
                    level: 1,
                },
                
                attributes: ['id', 'role_id']
            });
        • findAndCountAll
        await Role.findAndCountAll({
                where: {
                    level: 1,
                }
            });
        • all()是 findAll 的別名
         await Role.all({
                where: {
                    level: {
                        [Op.gt]: 1,
        
                        // [Op.and]: {a: 5},           // AND (a = 5)
                        // [Op.or]: [{a: 5}, {a: 6}],  // (a = 5 OR a = 6)
                        // [Op.gt]: 6,                // id > 6
                        // [Op.gte]: 6,               // id >= 6
                        // [Op.lt]: 10,               // id < 10
                        // [Op.lte]: 10,              // id <= 10
                        // [Op.ne]: 20,               // id != 20
                        // [Op.between]: [6, 10],     // BETWEEN 6 AND 10
                        // [Op.notBetween]: [11, 15], // NOT BETWEEN 11 AND 15
                        // [Op.in]: [1, 2],           // IN [1, 2]
                        // [Op.notIn]: [1, 2],        // NOT IN [1, 2]
                        // [Op.like]: '%hat',         // LIKE '%hat'
                        // [Op.notLike]: '%hat',      // NOT LIKE '%hat'
                        
                        $and: {a: 5}           // AND (a = 5)
                        $or: [{a: 5}, {a: 6}]  // (a = 5 OR a = 6)
                        $gt: 6,                // > 6
                        $gte: 6,               // >= 6
                        $lt: 10,               // < 10
                        $lte: 10,              // <= 10
                        $ne: 20,               // != 20
                        $not: true,            // IS NOT TRUE
                        $between: [6, 10],     // BETWEEN 6 AND 10
                        $notBetween: [11, 15], // NOT BETWEEN 11 AND 15
                        $in: [1, 2],           // IN [1, 2]
                        $notIn: [1, 2],        // NOT IN [1, 2]
                        $like: '%hat',         // LIKE '%hat'
                        $notLike: '%hat'       // NOT LIKE '%hat'
                        $iLike: '%hat'         // ILIKE '%hat' (case insensitive) (PG only)
                        $notILike: '%hat'      // NOT ILIKE '%hat'  (PG only)
                        $like: { $any: ['cat', 'hat']}
                                               // LIKE ANY ARRAY['cat', 'hat'] - also works for iLike and notLike
                        $overlap: [1, 2]       // && [1, 2] (PG array overlap operator)
                        $contains: [1, 2]      // @> [1, 2] (PG array contains operator)
                        $contained: [1, 2]     // <@ [1, 2] (PG array contained by operator)
                        $any: [2,3]            // ANY ARRAY[2, 3]::INTEGER (PG only)
                        
                        $col: 'user.organization_id' // = "user"."organization_id", with dialect specific column identifiers, PG in this example
                    }
                },
                limit: 3,
                // 注意 raw, 默認為 false, 這時候 Sequelize 會為搜索出的每一條數據生成一個 Role 實例,用于更新,刪除等操作
                // 但當我們只想搜索出數據用于顯示,并不想操作它,這個時候設置 raw: true 就會直接返回數據,而不會生成實例
                raw: true,
            });
        • count

        await Role.count();

        • findAndCountAll
        await Role.findAndCountAll({
             where: {
                title: {
                  [Op.like]: 'foo%'
                }
             },
             offset: 10,
             limit: 2
          })
        • findAndCountAll
        await Role.findAndCountAll({
             where: {
                title: {
                  [Op.like]: 'foo%'
                }
             },
             offset: 10,
             limit: 2
          })
        • 查詢結果重命名
        const user = await User.findOne({
            where:{
                id:userId
            },
            attributes:[['id','user_id'],['username','user_name']]
        })
        • order
        await Role.findAll({
            'order': "id DESC"
        });
        
        Role.findAll({
          order: [
            // 將轉義用戶名,并根據有效的方向參數列表驗證DESC
            ['title', 'DESC'],
        
            // 將按最大值排序(age)
            sequelize.fn('max', sequelize.col('age')),
        
            // 將按最大順序(age) DESC
            [sequelize.fn('max', sequelize.col('age')), 'DESC'],
        
            // 將按 otherfunction 排序(`col1`, 12, 'lalala') DESC
            [sequelize.fn('otherfunction', sequelize.col('col1'), 12, 'lalala'), 'DESC'],
        
            // 將使用模型名稱作為關聯的名稱排序關聯模型的 created_at。
            [Task, 'createdAt', 'DESC'],
        
            // Will order through an associated model's created_at using the model names as the associations' names.
            [Task, Project, 'createdAt', 'DESC'],
        
            // 將使用關聯的名稱由關聯模型的created_at排序。
            ['Task', 'createdAt', 'DESC'],
        
            // Will order by a nested associated model's created_at using the names of the associations.
            ['Task', 'Project', 'createdAt', 'DESC'],
        
            // Will order by an associated model's created_at using an association object. (優選方法)
            [Subtask.associations.Task, 'createdAt', 'DESC'],
        
            // Will order by a nested associated model's created_at using association objects. (優選方法)
            [Subtask.associations.Task, Task.associations.Project, 'createdAt', 'DESC'],
        
            // Will order by an associated model's created_at using a simple association object.
            [{model: Task, as: 'Task'}, 'createdAt', 'DESC'],
        
            // 嵌套關聯模型的 created_at 簡單關聯對象排序
            [{model: Task, as: 'Task'}, {model: Project, as: 'Project'}, 'createdAt', 'DESC']
          ]
          
          // 將按年齡最大值降序排列
          order: sequelize.literal('max(age) DESC')
        
          // 按最年齡大值升序排列,當省略排序條件時默認是升序排列
          order: sequelize.fn('max', sequelize.col('age'))
        
          // 按升序排列是省略排序條件的默認順序
          order: sequelize.col('age')
        })
        • limit
        // 獲取10個實例/行
        Project.findAll({ limit: 10 })
        • offset
        // 跳過8個實例/行
        Project.findAll({ offset: 8 })
        
        • max
        await Role.max('level', {
                where: {
                    id: {
                        [Op.gt]: 5,
                    }
                }
            });
        • sum
        await Role.sum('level');
        • COUNT,AVG,MAX,MIN,SUM等函數
        //  可以使用sequelize.fn來執行這些函數
        Role.findAll({
            attributes: [[sequelize.fn('COUNT', sequelize.col('*')), 'total_count']],
        });
        // SELECT COUNT(*) AS `total_count` ...
        
        Role.findAll({
            attributes: [[sequelize.fn('COUNT', 1), 'total_count']],
        });
        // SELECT COUNT(1) AS `total_count` ...
        • OR寫法
        Role.findAll({
            where: {
              [Op.or]: [{ id: 2 }, { id: 3 }],
            },
        });
        // ... where `role`.`id` = 2 OR `role`.`id` = 3
          
        // 另一種寫法
        Role.findAll({
            where: {
              id: {
                [Op.or]: [2, 3],
              },
            },
        });
        // ... where `role`.`id` = 2 OR `role`.`id` = 3
         
        // 不同字段的寫法
        Role.findAll({
            where: {
              [Op.or]: [{ id: 2 }, { level: 3 }],
            },
        });
        // ... where `role`.`id` = 2 OR `role`.`level` = 3
        
        Role.findAll({
            where: {
              [Op.or]: [{ id: 2 }, { level: 3 }],
              [Op.and]: [{ role_id: { [Op.ne]: 10001 } }],
            },
        });
        // ... where (`role`.`id` = 2 OR `role`.`level` = 3) AND (`role`.`role_id` != 10001)
        • findOrCreate
        await Role.findOrCreate({
                where: {
                    role_name: 'alex'
                },
                defaults: {
                    role_id: 5,
                    role_name: 'alex',
                    level: 15,
                },
            });

        新建

        • 創建一個沒有寫入數據庫的實例,用save命令存入數據庫中
        const role = Role.build({
            role_id: 1,
            role_name: 'name-1'
        });
        await role.save(); // 在需要的時候調用 save 命令,可以將數據存入數據庫中
        • 直接使用create命令直接創建一條寫入數據庫的數據
        await Role.create({
            role_id: 2,
            role_name: 'name-2',
        });
        • 批量創建實例
        const l = [];
        for (let i = 0; i < 5; i++) {
            l.push({
                role_id: 1000 + i,
                role_name: `bulkname-${i}`,
                level: i + 5,
            });
        }
        
        const result = await Role.bulkCreate(l, {
            // 這樣創建語句中只有 role_id 和 role_name,會忽略 level
            fields: ['role_id', 'role_name']
        });

        更新

        • 查詢同時更新
        await Role.update({
            level: 4
        }, {
            where: {}
        });
        
        • 先查詢,后更新
        const role = await Role.findOne({
            where: {}
        });
        await role.update({
            // 注意這個role不是原型Role
            level: 5
        });

        增減

        • 增加值使用increment, 減少值使用decrement,用法相同
        // level加5
        const role = await Role.findById(1);
        await role.increment('level', {
            by: 5
        });

        刪除

        • 批量刪除
        await Role.destroy({
            where: {
                id: 1
            }
        });

        sequelize.query(原生sql)

        默認情況下,函數將返回兩個參數 - 一個結果數組,以及一個包含元數據(受影響的行等)的對象。 請注意,由于這是一個原始查詢,所以元數據(屬性名稱等)是具體的方言。 某些方言返回元數據 "within" 結果對象(作為數組上的屬性)。 但是,將永遠返回兩個參數,但對于MSSQL和MySQL,它將是對同一對象的兩個引用。

         const result1 =  await mysql.query('SELECT id, img_url, url from carousel where status = 1');
         //返回值是兩個相同元素組成的數組
         "result1": [
                [
                    {
                        "id": 1,
                        "url": "/ClassDetail?id=4"
                    },
                    {
                        "id": 4,
                        "url": "/ClassDetail?id=2"
                    }
                ],
                [
                    {
                        "id": 1,
                        "url": "/ClassDetail?id=4"
                    },
                    {
                        "id": 4,
                        "url": "/ClassDetail?id=2"
                    }
                ]
            ]

        解決辦法有兩種

        1. 傳遞一個查詢類型來告訴后續如何格式化結果
          const result= await mysql.query('SELECT id, img_url, url from carousel where status = 1', {
            replacements: {},
            type: mysql.QueryTypes.SELECT
          });
        1. 傳遞模型
        const Carousel = require('../../models/Carousel');
        
        const result2 = await mysql.query('SELECT id, img_url, url from carousel where status = 1',{ model: Carousel });

        替換

        查詢中的替換可以通過兩種不同的方式完成:使用命名參數(以:開頭),或者由?表示的未命名參數。 替換在options對象中傳遞。

        • ?

        如果傳遞一個數組, ? 將按照它們在數組中出現的順序被替換

        const banner2 = await mysql.query('SELECT id, img_url, url from carousel where id = ?', {
            replacements: [1,4,5,6],
            type: mysql.QueryTypes.SELECT,
        });
        // 返回的結果只有數組第一個元素下標對應的數據
        const banner3 = await mysql.query('SELECT id, img_url, url from carousel where id in (:[1,4,5,6])', {
            replacements: {[1,4,5,6]},
            type: mysql.QueryTypes.SELECT,
        });
        // 返回結果為符合數組的數據
        
        // 拓展:模糊查詢
        sequelize.query('SELECT * FROM users WHERE name LIKE :search_name ',
          { replacements: { search_name: 'ben%'  }, type: sequelize.QueryTypes.SELECT }
        ).then(projects => {
          console.log(projects)
        })
        
        注意:
        type: mysql.QueryTypes.SELECT
        進行不同的原生操作是, QueryTypes的取值也不相同,這里誤以為都是select坑死

        參考文檔:
        官方文檔
        Sequelize 中文文檔 v4 - Raw queries - 原始查詢
        alex_my https://blog.csdn.net/alex_my...

        查詢結果

        如果不想讓它自動包裝,可以在查詢的時候,設置一個參數就會返回查詢的源數據

        Model.findAll({
         raw: true, // 設置為 true,即可返回源數據
         //Other parameters
        });

        也可以在初始化 Sequelize 的時候直接全局設置:

        const sequelize = new Sequelize('connectionUri', {
         define: {
          raw: true  // 設置為 true,即可返回源數據
         } 
        });
        
        查看原文

        贊 1 收藏 0 評論 0

        旅圖灬 贊了文章 · 3月25日

        Vue 拖拽實現及問題備忘

        以下備忘拖拽的簡單實現和其中存在的問題,以此為基石可以擴展開發多種拖拽效果。

        1. 拖拽樣式

        如下圖,我們想實現的效果為:

        當方塊從上方灰塊被拖拽到下方時,下方灰塊中會出現該方塊。

        讓我們先把以上頁面效果實現:

        <style scoped>
            .drag-field,
            .drop-field{
                height: 10rem;
                box-sizing: border-box;
                padding: 1rem;
                background-color: #eee;
                margin-top: 1rem;
                display: flex;
                justify-content: space-around;
                align-items: center;
            }
        
            .item{
                width: 30%;
                height: 3rem;
                text-align: center;
                line-height: 3rem;
                font-size: .9rem;
                background-color: royalblue;
                color: #eee;
            }
            .item:hover{
                cursor: pointer;
            }
        </style>
        
        <template>
            <div class="hello">
                <div class="drag-field">
                    <div class="item"
                         v-for="(item, index) in items" :key="index"
                    >
                        {{ item.label }}
                    </div>
                </div>
                <div class="drop-field">
                    <div class="item" v-if="droppedItem !== ''">
                        {{ droppedItem }}
                    </div>
                </div>
            </div>
        </template>
        
        <script>
        /* eslint-disable */
            export default {
                name: '',
                data () {
                    return {
                        droppedItem: '',
                        items: [
                            {
                                id: 1,
                                label: '模塊一'
                            },
                            {
                                id: 2,
                                label: '模塊二'
                            },
                            {
                                id: 3,
                                label: '模塊三'
                            }
                        ]
                    }
                }
            }
        </script>

        2. 拖拽相關事件

        為了讓 DOM 元素可以拖拽,我們需要為元素增加 draggable="true"

        <div class="item"
             draggable="true"
             v-for="(item, index) in items" :key="index"
        >
            {{ item.label }}
        </div>

        2.1 拖拽事件介紹

        • @dragstart:拖拽開始事件,可綁定于被拖拽元素上;
        • @dragend:拖拽結束事件,可綁定于被拖拽元素上;
        • @dragover:拖拽持續移動事件,建議綁定于可拖放區域(下方灰色塊);
        • @dragenter:進入拖放區域,建議綁定于可拖放區域(下方灰色塊),該事件僅在進入拖放區域時觸發,在其內部移動時不觸發,離開某一可拖放區域后再進入時會再次觸發;

        2.2 ondrop

        拖放事件,綁定于可拖放區域上。

        之所以把這個方法單獨拎出來,是因為在使用該方法時存在一些注意事項。

        當我們這樣使用時:

        <div class="drop-field"
             @drop="drop"
        >
            ...
        </div>
        
        
        methods: {
            drop (event) {
                console.log('drop', event)
            }
        }

        發現當我們將可拖拽元素拖放至此時,并沒有觸發事件。

        根據 MDN 的文檔:

        A listener for the dragenter and dragover events are used to indicate valid drop targets, that is, places where dragged items may be dropped. Most areas of a web page or application are not valid places to drop data. Thus, the default handling for these events is to not allow a drop.", hence the only way for the drop event to be fired is to first cancel the dragenter or dragover event.

        我們必須阻止某一 DOM 元素對 dragover 的默認行為,才能使 drop 事件在其上正確執行:

        <div class="drop-field"
             @drop="drop"
             @dragover="dragover"
        >
            ...
        </div>
        
        methods: {
            drop (event) {
                console.log('drop', event)
            },
            dragover (event) {
                event.preventDefault()
            }
        }

        在 Vue 中,我們可以將組織默認行為的過程簡寫如下:

        @dragover="dragover"
        
        # 改為:
        
        @dragover.prevent

        2.3 DragEvent

        注意,無論是 dragxxx 或 drop 事件,其傳遞的參數都是 DragEvent。

        讓我很費解的是,對于在拖放區綁定的 drop 事件而言,其 DragEvent 中竟然無法找到被拖拽元素。

        這也就意味著,不借助額外變量,drop 事件是無法知道被拖放者是什么的。

        但我們仍可以借助 DragEvent 中的 DataTransfer 來進行被拖放對象的消息傳遞。

        流程如下:

        2.3.1 在被拖拽對象的 dropstart 事件中傳遞消息

        <div class="item"
             draggable="true"
             @dragstart="dragstart"
             v-for="(item, index) in items" :key="index"
        >
            {{ item.label }}
        </div>
        
        
        dragstart (event) {
            console.log('dragstart', event)
            event.dataTransfer.setData('my-info', 'hello')
            event.dataTransfer.setData('my-extra-info', 'world')
        }     

        2.3.2 在拖放區的 drop 事件中獲取消息

        <div class="drop-field"
             @drop="drop"
             @dragover.prevent
        >
            <div class="item"
                 v-if="droppedItem !== ''">
                {{ droppedItem }}
            </div>
        </div>
        
        drop (event) {
            console.log('drop', event)
            console.log(event.dataTransfer.getData('my-info'))
            console.log(event.dataTransfer.getData('my-extra-info'))
        }

        2.3.3 在被拖拽對象的 dragend 事件中清除消息

        <div class="item"
             draggable="true"
             @dragstart="dragstart"
             @dragend="dragend"
             v-for="(item, index) in items" :key="index"
        >
            {{ item.label }}
        </div>
        
        dragend (event) {
            console.log('dragend', event);
            event.dataTransfer.clearData()
        }

        2.3.4 注意事項一:不能在被拖拽對象的 dragend 事件中傳遞消息

        在整個拖拽過程中,事件的先后順序為:

        Step1: 拖拽對象的 dropstart;
        Step2: 拖放區的 drop;
        Step3:拖拽對象的 dropend;

        因而,如果在 dragend 中傳遞消息,是不能被 drop 捕獲的。

        2.3.5 注意事項二:不能在被拖拽對象的 dragover 事件中傳遞消息

        如果我們在被拖拽對象的 dragover 事件中傳遞消息,由于 dragover 事件的作用對象是「可拖放區」,即此時,該 dragover 中的 DragEvent 是以「可拖放區」身份施加的,故而不會傳遞到 drop 中。

        2.3.6 注意事項三:消息只能是 String 類型

        dataTransfer 中設置的消息( 即 setData 的第二個參數 )只能是字符串類型。如果想要傳遞對象,需要先進行序列化。

        2.3.7 注意事項四:Vue 中事件參數

        在上面的代碼中,如果我們在 @dragstart 中想傳遞一些參數,如下:

        @dragstart="dragstart(item)"

        就會遇到一個問題:默認傳遞的 DragEvent 參數丟失了。

        此時,我們需要使用 Vue 的特殊變量來實現事件參數的傳遞:

        @dragstart="dragstart($event, item)"

        3. 拖拽實現

        結合以上內容,我們的實現思路如下:

        代碼如下:

        <div class="item"
             draggable="true"
             @dragstart="dragstart($event, item)"
             @dragend="dragend"
             v-for="(item, index) in items" :key="index"
        >
            {{ item.label }}
        </div>
        
        <div class="drop-field"
             @drop="drop"
             @dragover.prevent
        >
            <div class="item"
                 v-if="droppedItem !== ''">
                {{ droppedItem }}
            </div>
        </div>
        
        
        methods: {
            drop (event) {
                this.droppedItem = event.dataTransfer.getData('item')
            },
            dragstart (event, item) {
                event.dataTransfer.setData('item', item.label)
            },
            dragend (event) {
                event.dataTransfer.clearData()
            }
        }

        在 Vue 項目中,被拖拽對象和可拖放區域可能放在不同組件之中,此時,關鍵數據的傳遞最好借助 Vuex 等數據總線實現。讓數據而非 DOM 流轉是 Vue 項目的基本思路。

        參考鏈接

        1. DataTransfer - Web API 接口 | MDN
        2. HTML5 drag & drop 拖拽與拖放簡介 ? 張鑫旭-鑫空間-鑫生活
        3. Vue.js里面點擊事件傳遞了參數還能使用事件參數嗎?如何使用? - radical的回答 - SegmentFault 思否
        4. DataTransfer.setData() - Web API 接口 | MDN
        5. HTML5 Drag and Drop events with Vue | Vue.js Discussion
        6. ondrop Event
        查看原文

        贊 42 收藏 28 評論 8

        旅圖灬 贊了文章 · 3月22日

        谷歌 Flutter 2.0 重磅發布!開源讓其蓬勃發展

        谷歌 Flutter 2.0 重磅發布!開源讓 Flutter 蓬勃發展

        谷歌剛剛發布了 Flutter 2.0 版本,它是 Flutter 的重大升級,借助Flutter 2.0 開發人員能從同一代碼庫構建跨平臺軟件,為任何平臺創建美觀、快速且可移植的應用程序。

        但是今天的發布會可能主要是為了強調 Flutter 繼續向移動應用過渡,不管它們在哪里都支持應用ーー網絡、桌面,甚至是新興的形式因素,如可折疊的應用。

        Flutter 2.0 取得與 Android 和 iOS 的“平等”地位

        在 2017 年的 I/O 開發者大會上,谷歌首次推出了 Flutter,它的 1.0 版本于 2018 年 12 月問世。支持 Android 和 iOS 應用程序,但是在此后的兩年多時間里,谷歌在一定程度上擴展了對 web 應用、 MacOS、 Linux、 Windows 甚至嵌入式設備的支持。然而,這種支持只是在早期階段提供的,要么是大多數開發人員無法獲得的,要么不是為生產級應用設計的。

        自 2019 年以來,Flutter 的網絡開發工具包一直處于測試階段,但今天它與 Android 和 iOS 這些“兄弟們”取得了平等的地位。對于桌面開發者來說,谷歌已經將 Flutter For Windows、 MacOS 和 Linux 過渡到主要的“穩定”發行版。

        Flutter 產品經理 Tim Sneath 向外媒透露,“這對我們來說是一個巨大的里程碑,不僅因為代碼本身已經可以用于高質量的產品,還因為過去只有極少數的 Flutter 用戶可以使用它,這些用戶正在運行發布前的軟件開發工具包?!?/p>

        Flutter 使用 Google 自己的 Dart 編程語言,旨在幫助開發人員構建在其所運行的每個平臺上都感覺原生的應用程序,同時盡可能多地共享代碼以避免重復工作。

        Flutter 2.0 現在支持使用相同的代碼庫將本機應用程序發布到五個操作系統:iOS、Android、Windows、macOS 和 Linux; Windows Vista、Windows XP 和 Windows XP。以及針對 Chrome、Firefox、Safari 或 Edge 等瀏覽器的網絡體驗。Flutter 甚至可以嵌入到汽車,電視和智能家電中,為環境計算世界提供最普遍和最便攜式的體驗。

        image.png

        Flutter 開發套件的大量改進

        在設計應用程序時,開發者需要考慮無數特定于平臺的因素,包括人們如何與他們的設備互動(例如,移動設備上的觸摸和滑動,桌面上的鍵盤和鼠標),用戶在不同的屏幕尺寸上消費內容,甚至他們用來寫作的語言。這就是為什么花一些時間才能在發行周期中改進各種 Flutter 開發套件的原因。

        Tim Sneath 說:“為了達到這個階段,我們做了大量的工作,包括增加國際化支持,例如針對中文等語言的 IME 編輯器,針對桌面支持的 TreeView 和 DataTable 等新小工具,以及對 Apple Silicon 驅動開發機器的更好支持?!?/p>

        特別是在 Linux 方面,為 Ubuntu 相關項目提供商業化服務的公司 Canonical 今天透露,Flutter 現在已經成為 Ubuntu 操作系統桌面和移動應用程序開發的默認框架。 去年 7 月,谷歌和 Canonical 啟動了 Flutter 向 Linux 領域的擴展,并促使 Canonical 的工程師為 Flutter 項目貢獻了代碼。

        作為最新擴展的一部分,Canonical 公布了一個基于 Flutter 的 Ubuntu 安裝程序的早期演示。

        image.png

        今天宣布的其他值得注意的 Flutter 更新包括 Google Mobile Ads SDK 的 beta 版本,該版本一直處于早期的試驗模式,為 AdMob 和 AdManager 提供了各種廣告格式。谷歌還推出了 Flutter 插件更新,涵蓋了各種 Firebase 服務,包括身份驗證、 Crashlytics、云消息和云存儲。

        與此同時,Dart 今天發布了 2.12 版本,支持 null 安全(或“ void safety”),以避免 null 異常。

        Flutter 解決了大公司的兩個核心挑戰

        去年四月,谷歌透露每月有50萬開發者使用 Flutter。差不多一年過去了,谷歌沒有提供任何關于這個數字的更新,只是說“用戶數量還在繼續增長”,但今天,谷歌表示,Google Play Store 上有15萬個 Flutter 支持的應用程序。它不具備其他應用程序商店,如蘋果商店提供的,來自其他地方的數據的同樣跟蹤能力。

        Tim Sneath 說:“有趣的是,我們知道有些應用程序在其中為一個移動平臺添加了 Flutter 應用程序,然后將其回滾到另一個移動平臺?!?/p>

        早在去年九月,谷歌支付就開始使用 Flutter,并將其添加到谷歌分析、谷歌廣告、谷歌購物、谷歌 Nest Hub、體育場和其他谷歌產品中,這些產品已經在使用這個開發工具包。

        Flutter 是快速和一致的跨平臺編碼,但也是一個相對年輕的框架,第三方軟件庫和限制開發人員的軟件包較少。因此,對于更大、更復雜的企業應用程序,本地軟件開發方法可能仍將是大多數公司的首選方法。

        Tim Sneath 強調,“生態系統不會在一夜之間發展起來,從某些標準來看,Flutter 仍然是一個新平臺。但我們相信上述 15000 個軟件包和代表的公司(例如 Nubank 和 Realtor 是在填補剩余空白方面快速發展的證據,這種持續增長令我們深受鼓舞?!?/p>

        有明確的證據表明,企業對 Flutter 必須提供的服務感興趣,擁有大量 vc 支持的 Nubank 甚至公布了它為什么使用 Flutter 進行跨平臺移動開發的全部理念。根據 Sneath 的說法,Flutter 解決了大公司的兩個核心挑戰。

        他說: “首先,他們發現,為了接觸到所有的客戶,他們必須創建同一個應用程序兩次、三次、甚至四次或更多次,這令人惱火?!??!斑@種復制沒有好的并行機制——他們不建立多計費系統、多工資單平臺等。這是一種浪費,而且會導致各種各樣的二階問題: 如何將多個應用程序模擬到多個平臺上,是否所有的開發團隊都必須以最慢的速度運行,等等?!?/p>

        Sneath 認為,Flutter 解決的第二個問題是,企業可能會投入數百萬美元創建和維護一系列企業品牌,但由于其內在的局限性,它們可能會受到限制,無法利用自己的數字屬性。

        image.png

        開源讓 Flutter 蓬勃發展

        在過去的十年中,開源運動得到了極大的發展,大多數主要的技術公司都在某種程度上接受了它。Facebook 已經開放了無數的內部項目,而谷歌本身對開源并不陌生。與此同時,微軟一直在努力展示它在開源方面的全力以赴,最近還宣稱它現在已經成為跨公司協作的公認模式。

        谷歌可能是 Flutter 框架的最大貢獻者,但這并不能說明全部情況。Sneath 提到,在所有參與這次發布的個人中,大多數都不在谷歌工作。他說:“當然,Flutter 不僅僅是一個核心框架,目前大約有 15000 個軟件包,其中絕大多數來自非谷歌貢獻者,如亞馬遜、微軟、 Adobe、華為、阿里巴巴、 eBay 和 Square?!?/p>

        在最新版的 Flutter 中,微軟做出了一些顯著的貢獻,特別是圍繞其迅速增長的關注“可折疊”的外形因素,這可能需要設備的雙屏幕。微軟現在正在發布支持這些新設計的代碼,允許應用程序利用其獨特的功能。

        這也突顯出為什么開源對這個項目有意義,谷歌需要整個行業和生態系統的支持,才能讓 Flutter 蓬勃發展,而且如果開發者能夠完全訪問代碼庫,他們就更有可能留下來。

        Sneath 說:“軟件開發人員能夠看到整個堆棧的代碼,這對 UI 框架來說是一個巨大的加分點。能夠通過層進行調試,而不是直接進入黑盒子,這會提高開發人員的效率。如果一個控件或小部件不能完全滿足您的需求,那么能夠接受它并將其分支出去,這樣可以確??蚣鼙旧碛肋h不會成為一個限制因素。從一個純粹自私的角度來看,開源意味著我們可以從一個有才華的社區獲得貢獻。能夠讓我們的客戶同時提交一個 bug 和一個修復,或者私下修復某些東西,是另一個巨大的優勢?!?/p>

        現在,開發者已經可以開始使用 Flutter 2.0 了。

        參考鏈接:https://developers.googleblog.com/2021/03/announcing-flutter-2.html

        https://venturebeat.com/2021/03/03/google-launches-flutter-2-0-to-target-developers-across-all-platforms/

        GitHub 地址:https://github.com/flutter/flutter

        segmentfault 公眾號

        查看原文

        贊 4 收藏 2 評論 0

        旅圖灬 發布了文章 · 3月19日

        commitizen 安裝后執行 git-cz 彈出 vim窗口

        commitzencz-conventional-changelog需要搭配使用,
        一開始以為不需要寫入log記錄,就沒安裝,導致執行git-cz命令時,并未出現想要的交互效果。

        配置 安裝好commitzencz-conventional-changelog之后,還需要添加一些配置:
        package.json 中添加:

        "scripts": {
          "commit": "git-cz"
        },
        "config": {
          "commitizen": {
            "path": "node_modules/cz-conventional-changelog"
          }
        }

        在配置中,我們需要指定 Adapter,否則在執行git-cz的時候,不會出現選擇的交互界面,而是直接彈出 vim 編輯器編輯 message。

        配置好之后使用npm run commit替代git commit提交。

        查看原文

        贊 0 收藏 0 評論 0

        旅圖灬 贊了文章 · 3月18日

        一篇文章帶你入門Mongoose

        走在前端的大道上

        Mongoose是在node.js環境下對mongodb進行便捷操作的對象模型工具

        因此,要使用mongoose,則必須安裝node.js環境以及mongodb數據庫。mongoose使mongodb操作更簡單便捷??梢栽?a rel="nofollow noreferrer"> github 中獲得其源碼,也可以在這里查看 api 文檔,英文的。

        安裝

          
        安裝nodejs和mongodb之后 ,使用npm來安裝mongoose

        npm install mongoose --save

        安裝成功后,就可以通過 require('mongoose') 來使用


        connect

        connect 用于創建數據庫連接

        mongoose.connect(url(s), [options], [callback])
        //url(s):數據庫地址,可以是多個,以`,`隔開
        //options:可選,配置參數
        //callback:可選,回調
        mongoose.connect('mongodb://數據庫地址(包括端口號)/數據庫名稱')

        指定用戶連接

        mongoose.connect('mongodb://用戶名:密碼@127.0.0.1:27017/數據庫名稱')

        連接多個數據庫

        如果你的app中要連接多個數據庫,只需要設置多個url以,隔開,同時設置mongos為true

        mongoose.connect('urlA,urlB,...', {
           mongos : true 
        })

        回調參數

        mongoose.connect(url, options, function(error) {
        
        });

        執行下列代碼后,控制臺輸出“連接成功”

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://localhost/test", function(err) {
            if(err){
                console.log('連接失敗');
            }else{
                console.log('連接成功');
            }
        });

         如果開啟鑒權控制,以用戶名"u1",密碼"123456"登錄'db1'數據庫。執行代碼后,控制臺輸出“連接成功”

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(err){
                console.log('連接失敗');
            }else{
                console.log('連接成功');
            }
        });

        簡單實驗

        創建一個db.js

        var mongoose = require('mongoose'),
            DB_URL = 'mongodb://localhost:27017/mongoosesample';
        
        /**
         * 連接
         */
        mongoose.connect(DB_URL);
        
        /**
          * 連接成功
          */
        mongoose.connection.on('connected', function () {    
            console.log('Mongoose connection open to ' + DB_URL);  
        });    
        
        /**
         * 連接異常
         */
        mongoose.connection.on('error',function (err) {    
            console.log('Mongoose connection error: ' + err);  
        });    
         
        /**
         * 連接斷開
         */
        mongoose.connection.on('disconnected', function () {    
            console.log('Mongoose connection disconnected');  
        });    

          調用node db.js執行就會看到輸出如下圖

        clipboard.png


        disconnect()

        mongoose.disconnect()

        使用disconnect()方法可以斷開連接

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(err){
                console.log('連接失敗');
            }else{
                console.log('連接成功');
            }
        });
        setTimeout(function(){
            mongoose.disconnect(function(){
                console.log("斷開連接");
            })
        }, 2000);

        clipboard.png


        Schema

        Schema主要用于定義MongoDB中集合Collection里文檔document的結構,可以理解為mongoose對表結構的定義(不僅僅可以定義文檔的結構和屬性,還可以定義文檔的實例方法、靜態模型方法、復合索引等),每個schema會映射到mongodb中的一個collection,schema不具備操作數據庫的能力

         定義Schema非常簡單,指定字段名和類型即可,支持的類型包括以下8種

        String      字符串
        Number      數字    
        Date        日期
        Buffer      二進制
        Boolean     布爾值
        Mixed       混合類型
        ObjectId    對象ID    
        Array       數組

         通過mongoose.Schema來調用Schema,然后使用new方法來創建schema

        var mongoose = require('mongoose');
        var Schema = mongoose.Schema;
        
        var mySchema = new Schema({
          title:  String,
          author: String,
          body:   String,
          comments: [{ body: String, date: Date }],
          date: { type: Date, default: Date.now },
          hidden: Boolean,
          meta: {
            votes: Number,
            favs:  Number
          }
        });

         注意 創建Schema對象時,聲明字段類型有兩種方法,一種是首字母大寫的字段類型,另一種是引號包含的小寫字段類型

        var mySchema = new Schema({title:String, author:String});
        //或者 
        var mySchema = new Schema({title:'string', author:'string'});

         如果需要在Schema定義后添加其他字段,可以使用add()方法

        var MySchema = new Schema;
        MySchema.add({ name: 'string', color: 'string', price: 'number' });

        Model

         Model是由Schema編譯而成的假想(fancy)構造器,具有抽象屬性和行為。Model的每一個實例(instance)就是一個document,document可以保存到數據庫和對數據庫進行操作。簡單說就是model是由schema生成的模型,可以對數據庫的操作。

          使用model()方法,將Schema編譯為Model。model()方法的第一個參數是模型名稱

        mongoose.model(`文檔名稱`, Schema)

          注意 一定要將model()方法的第一個參數和其返回值設置為相同的值,否則會出現不可預知的結果

          Mongoose會將集合名稱設置為模型名稱的小寫版。如果名稱的最后一個字符是字母,則會變成復數;如果名稱的最后一個字符是數字,則不變;如果模型名稱為"MyModel",則集合名稱為"mymodels";如果模型名稱為"Model1",則集合名稱為"model1"

        var schema = new mongoose.Schema({ num:Number, name: String, size: String});
        var MyModel = mongoose.model('MyModel', schema);

        【實例化文檔document】

          通過對原型Model1使用new方法,實例化出文檔document對象

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(err){
                console.log('連接失敗');
            }else{
                console.log('連接成功');
                var schema = new mongoose.Schema({ num:Number, name: String, size: String});
                var MyModel = mongoose.model('MyModel', schema);
                var doc1 = new MyModel({ size: 'small' });
                console.log(doc1.size);//'small'
            }
        });

        【文檔保存】

          通過new Model1()創建的文檔doc1,必須通過save()方法,才能將創建的文檔保存到數據庫的集合中,集合名稱為模型名稱的小寫復數版

          回調函數是可選項,第一個參數為err,第二個參數為保存的文檔對象

        save(function (err, doc) {})
        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(!err){
                var schema = new mongoose.Schema({ num:Number, name: String, size: String });
                var MyModel = mongoose.model('MyModel', schema);
                var doc1 = new MyModel({ size: 'small' });
                doc1.save(function (err,doc) {
                //{ __v: 0, size: 'small', _id: 5970daba61162662b45a24a1 }
                  console.log(doc);
                })
            }
        });

          由下圖所示,db1數據庫中的集合名稱為mymodels,里面有一個{size:"small"}的文檔

        clipboard.png

        自定義方法
        【實例方法】

          Model的實例是document,內置實例方法有很多,如 save,可以通過Schema對象的methods屬性給實例自定義擴展方法

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(!err){
                var schema = new mongoose.Schema({ num:Number, name: String, size: String });        
                schema.methods.findSimilarSizes = function(cb){
                    return this.model('MyModel').find({size:this.size},cb);
                }
                var MyModel = mongoose.model('MyModel', schema);
                var doc1 = new MyModel({ name:'doc1', size: 'small' });
                var doc2 = new MyModel({ name:'doc2', size: 'small' });
                var doc3 = new MyModel({ name:'doc3', size: 'big' });
                doc1.save();
                doc2.save();
                doc3.save();
                setTimeout(function(){
                    doc1.findSimilarSizes(function(err,docs){
                        docs.forEach(function(item,index,arr){
                            //doc1
                            //doc2
                             console.log(item.name)        
                        })
                    })  
                },0)  
            }
        });

        【靜態方法】

          通過Schema對象的statics屬性給 Model 添加靜態方法

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(!err){
                var schema = new mongoose.Schema({ num:Number, name: String, size: String });        
                schema.statics.findByName = function(name,cb){
                    return this.find({name: new RegExp(name,'i')},cb);
                }
                var MyModel = mongoose.model('MyModel', schema);
                var doc1 = new MyModel({ name:'doc1', size: 'small' });
                var doc2 = new MyModel({ name:'doc2', size: 'small' });
                var doc3 = new MyModel({ name:'doc3', size: 'big' });
                doc1.save();
                doc2.save();
                doc3.save();
                setTimeout(function(){
                    MyModel.findByName('doc1',function(err,docs){
                        //[ { _id: 5971e68f4f4216605880dca2,name: 'doc1',size: 'small',__v: 0 } ]
                        console.log(docs);
                    })  
                },0)  
            }
        });

          由上所示,實例方法和靜態方法的區別在于,靜態方法是通過Schema對象的statics屬性給model添加方法,實例方法是通過Schema對象的methods是給document添加方法

        【Methods 和 Statics 的區別】

        statics是給model添加方法,methods是給實例(instance)添加方法。methods和statics的區別

        //module.exports = mongoose.model(`Article`, ArticleSchema )
        //將article的model保存為文件 article.js
        
        const Article = require('../models/article')
        
        // statics
        Article.staticFunc ()
        
        //methods
        const article = new Article(arguments)
        article.methodFunc()

        【查詢方法】

          通過schema對象的query屬性,給model添加查詢方法

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(!err){
                var schema = new mongoose.Schema({ age:Number, name: String});        
                schema.query.byName = function(name){
                    return this.find({name: new RegExp(name)});
                }
                var temp = mongoose.model('temp', schema);   
                temp.find().byName('huo').exec(function(err,docs){
                    //[ { _id: 5971f93be6f98ec60e3dc86c, name: 'huochai', age: 27 },
                    // { _id: 5971f93be6f98ec60e3dc86e, name: 'huo', age: 30 } ]
                    console.log(docs);
                })  
        
            }           
        });

        文檔新增

        文檔新增有三種方法,一種是使用上面介紹過的文檔的save()方法,另一種是使用模型model的create()方法,最后一種是模型model的insertMany()方法

        save()

          [注意]回調函數可以省略

        save([options], [options.safe], [options.validateBeforeSave], [fn])

          新建{age:10,name:'save'}文檔,并保存

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(!err){
                var schema = new mongoose.Schema({ age:Number, name: String});        
                var temp = mongoose.model('temp', schema);
                //使用鏈式寫法    
                new temp({age:10,name:'save'}).save(function(err,doc){
                    //[ { _id: 59720bc0d2b1125cbcd60b3f, age: 10, name: 'save', __v: 0 } ]
                    console.log(doc);        
                });         
            }           
        });

        create()

          使用save()方法,需要先實例化為文檔,再使用save()方法保存文檔。而create()方法,則直接在模型Model上操作,并且可以同時新增多個文檔

        Model.create(doc(s), [callback])

          新增{name:"xiaowang"},{name:"xiaoli"}這兩個文檔

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(!err){
                var schema = new mongoose.Schema({ age:Number, name: String});        
                var temp = mongoose.model('temp', schema);   
                temp.create({name:"xiaowang"},{name:"xiaoli"},function(err,doc1,doc2){
                    //{ __v: 0, name: 'xiaowang', _id: 59720d83ad8a953f5cd04664 }
                    console.log(doc1); 
                    //{ __v: 0, name: 'xiaoli', _id: 59720d83ad8a953f5cd04665 }
                    console.log(doc2); 
                });       
            }           
        });

        insertMany()

        Model.insertMany(doc(s), [options], [callback])
          新增{name:"a"},{name:"b"}這兩個文檔

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(!err){
                var schema = new mongoose.Schema({ age:Number, name: String});        
                var temp = mongoose.model('temp', schema);   
                temp.insertMany([{name:"a"},{name:"b"}],function(err,docs){
                    //[ { __v: 0, name: 'a', _id: 59720ea1bbf5792af824b30c },
                    //{ __v: 0, name: 'b', _id: 59720ea1bbf5792af824b30d } ]
                    console.log(docs); 
                });       
        
            }           
        });

        文檔查詢

        使用Mongoose來查找文檔很容易,有以下3種方法可供選擇

        find()
        findById()
        findOne()

        find()

          第一個參數表示查詢條件,第二個參數用于控制返回的字段,第三個參數用于配置查詢參數,第四個參數是回調函數,回調函數的形式為function(err,docs){}

        Model.find(conditions, [projection], [options], [callback])

          在數據庫db1的集合temps中存在如下數據

        clipboard.png

         現在,使用find()方法找出所有數據

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(!err){
                var schema = new mongoose.Schema({ age:Number, name: String});        
                var temp = mongoose.model('temp', schema);
                temp.find(function(err,docs){
                    //[ { _id: 5971f93be6f98ec60e3dc86c, name: 'huochai', age: 27 },
                    //{ _id: 5971f93be6f98ec60e3dc86d, name: 'wang', age: 18 },
                    //{ _id: 5971f93be6f98ec60e3dc86e, name: 'huo', age: 30 },
                    //{ _id: 5971f93be6f98ec60e3dc86f, name: 'li', age: 12 } ]
                    console.log(docs);
                })
            }
        });
        找出年齡大于18的數據
           temp.find({age:{$gte:18}},function(err,docs){
                //[ { _id: 5971f93be6f98ec60e3dc86c, name: 'huochai', age: 27 },
                //{ _id: 5971f93be6f98ec60e3dc86d, name: 'wang', age: 18 },
                //{ _id: 5971f93be6f98ec60e3dc86e, name: 'huo', age: 30 }]
                console.log(docs);
            })

          找出年齡大于18且名字里存在'huo'的數據

         temp.find({name:/huo/,age:{$gte:18}},function(err,docs){
                    //[ { _id: 5971f93be6f98ec60e3dc86c, name: 'huochai', age: 27 },
                    //{ _id: 5971f93be6f98ec60e3dc86e, name: 'huo', age: 30 }]
                    console.log(docs);
                })

          找出名字里存在'a'的數據,且只輸出'name'字段

          [注意]_id字段默認輸出

         temp.find({name:/a/},'name',function(err,docs){
            //[ { _id: 5971f93be6f98ec60e3dc86c, name: 'huochai' },
            //{ _id: 5971f93be6f98ec60e3dc86d, name: 'wang' } ]
             console.log(docs);
          })

          如果確實不需要_id字段輸出,可以進行如下設置

          temp.find({name:/a/},{name:1,_id:0},function(err,docs){
            //[ { name: 'huochai' }, { name: 'wang' } ]
             console.log(docs);
          })
        找出跳過前兩條數據的其他所有數據
        

          [注意]如果使用第三個參數,前兩個參數如果沒有值,需要設置為null

            temp.find(null,null,{skip:2},function(err,docs){
                //[ { _id: 5971f93be6f98ec60e3dc86e, name: 'huo', age: 30 },
                //{ _id: 5971f93be6f98ec60e3dc86f, name: 'li', age: 12 } ]
                console.log(docs);
            })

        findById()

        Model.findById(id, [projection], [options], [callback])

          顯示第0個元素的所有字段

            var aIDArr = [];
            temp.find(function(err,docs){
                docs.forEach(function(item,index,arr){
                    aIDArr.push(item._id);
                })
                temp.findById(aIDArr[0],function(err,doc){
                    //{ _id: 5971f93be6f98ec60e3dc86c, name: 'huochai', age: 27 }
                    console.log(doc);
                })            
            })

          以上代碼的另一種寫法如下

            var aIDArr = [];
            temp.find(function(err,docs){
                docs.forEach(function(item,index,arr){
                    aIDArr.push(item._id);
                })
                temp.findById(aIDArr[0]).exec(function(err,doc){
                    //{ _id: 5971f93be6f98ec60e3dc86c, name: 'huochai', age: 27 }
                    console.log(doc);
                })            
            })

          只輸出name字段

            temp.findById(aIDArr[0],{name:1,_id:0},function(err,doc){
                //{  name: 'huochai'}
                console.log(doc);
            })

          或者寫成下面這種形式

            temp.findById(aIDArr[0],{name:1,_id:0}).exec(function(err,doc){
                //{  name: 'huochai'}
                console.log(doc);
            })

          輸出最少的字段

            temp.findById(aIDArr[0],{lean:true},function(err,doc){
                //{ _id: 5971f93be6f98ec60e3dc86c }
                console.log(doc);
            })   
            temp.findById(aIDArr[0],{lean:true}).exec(function(err,doc){
                //{ _id: 5971f93be6f98ec60e3dc86c }
                console.log(doc);
            })     

        findOne()

        該方法返回查找到的所有實例的第一個

        Model.findOne([conditions], [projection], [options], [callback])

          找出age>20的文檔中的第一個文檔

            temp.findOne({age:{$gt : 20}},function(err,doc){
                //{ _id: 5971f93be6f98ec60e3dc86c, name: 'huochai', age: 27 }
                console.log(doc);
            })   
            temp.findOne({age:{$gt : 20}}).exec(function(err,doc){
                //{ _id: 5971f93be6f98ec60e3dc86c, name: 'huochai', age: 27 }
                console.log(doc);
            }) 

         找出age>20的文檔中的第一個文檔,且只輸出name字段

        temp.findOne({age:{$gt : 20}},{name:1,_id:0},function(err,doc){
            //{ name: 'huochai' }
            console.log(doc);
        })   
        temp.findOne({age:{$gt : 20}},{name:1,_id:0}).exec(function(err,doc){
            //{ name: 'huochai' }
            console.log(doc);
        })     

          找出age>20的文檔中的第一個文檔,且輸出包含name字段在內的最短字段

        temp.findOne({age:{$gt : 20}},"name",{lean:true},function(err,doc){
            //{ _id: 5971f93be6f98ec60e3dc86c, name: 'huochai' }
            console.log(doc);
        })   
        temp.findOne({age:{$gt : 20}},"name").lean().exec(function(err,doc){
            //{ _id: 5971f93be6f98ec60e3dc86c, name: 'huochai' }
            console.log(doc);
        })   

         文檔查詢中,常用的查詢條件如下

        $or    或關系
        $nor    或關系取反
        $gt    大于
        $gte    大于等于
        $lt    小于
        $lte    小于等于
        $ne    不等于
        $in    在多個值范圍內
        $nin    不在多個值范圍內
        $all    匹配數組中多個值
        $regex   正則,用于模糊查詢
        $size   匹配數組大小
        $maxDistance 范圍查詢,距離(基于LBS)
        $mod    取模運算
        $near    鄰域查詢,查詢附近的位置(基于LBS)
        $exists   字段是否存在
        $elemMatch 匹配內數組內的元素
        $within   范圍查詢(基于LBS)
        $box     范圍查詢,矩形范圍(基于LBS)
        $center   范圍醒詢,圓形范圍(基于LBS)
        $centerSphere 范圍查詢,球形范圍(基于LBS)
        $slice    查詢字段集合中的元素(比如從第幾個之后,第N到第M個元素

        $where

          如果要進行更復雜的查詢,需要使用$where操作符,$where操作符功能強大而且靈活,它可以使用任意的JavaScript作為查詢的一部分,包含JavaScript表達式的字符串或者JavaScript函數

        clipboard.png

        使用字符串

        temp.find({$where:"this.x == this.y"},function(err,docs){

        //[ { _id: 5972ed35e6f98ec60e3dc887,name: 'wang',age: 18,x: 1,y: 1 },
        //{ _id: 5972ed35e6f98ec60e3dc889, name: 'li', age: 20, x: 2, y: 2 } ]
        console.log(docs);

        })
        temp.find({$where:"obj.x == obj.y"},function(err,docs){

        //[ { _id: 5972ed35e6f98ec60e3dc887,name: 'wang',age: 18,x: 1,y: 1 },
        //{ _id: 5972ed35e6f98ec60e3dc889, name: 'li', age: 20, x: 2, y: 2 } ]
        console.log(docs);

        })

        使用函數

        temp.find({$where:function(){
                return obj.x !== obj.y;
            }},function(err,docs){
            //[ { _id: 5972ed35e6f98ec60e3dc886,name: 'huochai',age: 27,x: 1,y: 2 },
            //{ _id: 5972ed35e6f98ec60e3dc888, name: 'huo', age: 30, x: 2, y: 1 } ]
            console.log(docs);
        }) 
        temp.find({$where:function(){
                return this.x !== this.y;
            }},function(err,docs){
            //[ { _id: 5972ed35e6f98ec60e3dc886,name: 'huochai',age: 27,x: 1,y: 2 },
            //{ _id: 5972ed35e6f98ec60e3dc888, name: 'huo', age: 30, x: 2, y: 1 } ]
            console.log(docs);
        }) 

        文檔更新

        文檔更新可以使用以下幾種方法

        update()
        updateMany()
        find() + save()
        updateOne()
        findOne() + save()
        findByIdAndUpdate()
        fingOneAndUpdate()

        update()

          第一個參數conditions為查詢條件,第二個參數doc為需要修改的數據,第三個參數options為控制選項,第四個參數是回調函數

        Model.update(conditions, doc, [options], [callback])

          options有如下選項

           safe (boolean): 默認為true。安全模式。
          upsert (boolean): 默認為false。如果不存在則創建新記錄。
          multi (boolean): 默認為false。是否更新多個查詢記錄。
          runValidators: 如果值為true,執行Validation驗證。
          setDefaultsOnInsert: 如果upsert選項為true,在新建時插入文檔定義的默認值。
          strict (boolean): 以strict模式進行更新。
          overwrite (boolean): 默認為false。禁用update-only模式,允許覆蓋記錄。

          數據庫temps中現有數據如下

        clipboard.png

        現在使用update()方法查詢age大于20的數據,并將其年齡更改為40歲

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(!err){
                var schema = new mongoose.Schema({ age:Number, name: String});        
                var temp = mongoose.model('temp', schema);   
                temp.update({age:{$gte:20}},{age:40},function(err,raw){
                    //{ n: 1, nModified: 1, ok: 1 }
                    console.log(raw);
                })
        
            }           
        });

          經過以上操作,數據庫結果如下。只有第一個數據更改為40歲。而第三個數據沒有發生變化

        clipboard.png

          如果要同時更新多個記錄,需要設置options里的multi為true。下面將名字中有'a'字符的年齡設置為10歲

        var mongoose = require('mongoose');
        mongoose.connect("mongodb://u1:123456@localhost/db1", function(err) {
            if(!err){
                var schema = new mongoose.Schema({ age:Number, name: String});        
                var temp = mongoose.model('temp', schema);   
                temp.update({name:/a/},{age: 10},{multi:true},function(err,raw){
                    //{ n: 2, nModified: 2, ok: 1 }
                    console.log(raw);
                })
        
            }           
        });

        clipboard.png

        如果設置的查找條件,數據庫里的數據并不滿足,默認什么事都不發生

        temp.update({age:100},{name: "hundred"},function(err,raw){
            //{ n: 0, nModified: 0, ok: 1 }
            console.log(raw);
        })

          如果設置options里的upsert參數為true,若沒有符合查詢條件的文檔,mongo將會綜合第一第二個參數向集合插入一個新的文檔

        temp.update({age:100},{name: "hundred"},{upsert:true},function(err,raw){
            //{ n: 1, nModified: 0,upserted: [ { index: 0, _id: 5972c202d46b621fca7fc8c7 } ], ok: 1 }
            console.log(raw);
        })

        clipboard.png

        temp.update({name:/aa/},{age: 0},{upsert:true},function(err,raw){
            //{ n: 1, nModified: 0,upserted: [ { index: 0, _id: 5972c288d46b621fca7fdd8f } ], ok: 1 }
            console.log(raw);
        })

        clipboard.png

         [注意]update()方法中的回調函數不能省略,否則數據不會被更新。如果回調函數里并沒有什么有用的信息,則可以使用exec()簡化代碼

        temp.update({name:/aa/},{age: 0},{upsert:true}).exec();

        updateMany()

         updateMany()與update()方法唯一的區別就是默認更新多個文檔,即使設置{multi:false}也無法只更新第一個文檔

        Model.updateMany(conditions, doc, [options], [callback])

          將數據庫中名字中帶有'huo'的數據,年齡變為50歲

        temp.updateMany({name:/huo/},{age:50},function(err,raw){
            //{ n: 2, nModified: 2, ok: 1 }
            console.log(raw);
        });

        clipboard.png

        find() + save()

        如果需要更新的操作比較復雜,可以使用find()+save()方法來處理,比如找到年齡小于30歲的數據,名字后面添加'30'字符

        temp.find({age:{$lt:20}},function(err,docs){
            //[ { _id: 5971f93be6f98ec60e3dc86d, name: 'wang', age: 10 },
            //{ _id: 5971f93be6f98ec60e3dc86f, name: 'li', age: 12 }]
            console.log(docs);
            docs.forEach(function(item,index,arr){
                item.name += '30';
                item.save();
            })
            //[ { _id: 5971f93be6f98ec60e3dc86d, name: 'wang30', age: 10 },
            // { _id: 5971f93be6f98ec60e3dc86f, name: 'li30', age: 12 }]
            console.log(docs);
        });

        updateOne()

        updateOne()方法只能更新找到的第一條數據,即使設置{multi:true}也無法同時更新多個文檔

          將數據庫中名字中帶有'huo'的數據,年齡變為60歲

        temp.updateOne({name:/huo/},{age:60},function(err,raw){
            //{ n: 1, nModified: 1, ok: 1 }
            console.log(raw);
        });

        clipboard.png

        findOne() + save()

          如果需要更新的操作比較復雜,可以使用findOne()+save()方法來處理,比如找到名字為'huochai'的數據,年齡加100歲

        temp.findOne({name:'huochai'},function(err,doc){
            //{ _id: 5971f93be6f98ec60e3dc86c, name: 'huochai', age: 10 }
            console.log(doc);
            doc.age += 100;
            doc.save();
            //{ _id: 5971f93be6f98ec60e3dc86c, name: 'huochai', age: 110 }
            console.log(doc);
        });

        findOneAndUpdate()

          fineOneAndUpdate()方法的第四個參數回調函數的形式如下function(err,doc){}

        Model.findOneAndUpdate([conditions], [update], [options], [callback])

        findByIdAndUpdate

           fineByIdAndUpdate()方法的第四個參數回調函數的形式如下function(err,doc){}

        Model.findOneAndUpdate([conditions], [update], [options], [callback])

        文檔刪除

          有三種方法用于文檔刪除

        remove()
        findOneAndRemove()
        findByIdAndRemove()

        remove()

          remove有兩種形式,一種是文檔的remove()方法,一種是Model的remove()方法

          下面介紹Model的remove()方法,該方法的第一個參數conditions為查詢條件,第二個參數回調函數的形式如下function(err){}  

        model.remove(conditions, [callback])

        clipboard.png

          刪除數據庫中名稱包括'30'的數據

        temp.remove({name:/30/},function(err){})

        clipboard.png

         [注意]remove()方法中的回調函數不能省略,否則數據不會被刪除。當然,可以使用exec()方法來簡寫代碼

        temp.remove({name:/30/}).exec()

          下面介紹文檔的remove()方法,該方法的參數回調函數的形式如下function(err,doc){}

        document.remove([callback])

          刪除數據庫中名稱包含'huo'的數據

          [注意]文檔的remove()方法的回調函數參數可以省略

        temp.find({name:/huo/},function(err,doc){
            doc.forEach(function(item,index,arr){
                item.remove(function(err,doc){
                    //{ _id: 5971f93be6f98ec60e3dc86c, name: 'huochai', age: 30 }
                    //{ _id: 5971f93be6f98ec60e3dc86e, name: 'huo', age: 60 }
                    console.log(doc);
                })
            })
        })  

        clipboard.png

        findOneAndRemove()

        model的remove()會刪除符合條件的所有數據,如果只刪除符合條件的第一條數據,則可以使用model的findOneAndRemove()方法

        Model.findOneAndRemove(conditions, [options], [callback])

          集合temps現有數據如下

        clipboard.png

         現在刪除第一個年齡小于20的數據

        temp.findOneAndRemove({age:{$lt:20}},function(err,doc){
            //{ _id: 5972d3f3e6f98ec60e3dc873, name: 'wang', age: 18 }
            console.log(doc);
        })

        clipboard.png

        與model的remove()方法相同,回調函數不能省略,否則數據不會被刪除。當然,可以使用exec()方法來簡寫代碼

        temp.findOneAndRemove({age:{$lt:20}}).exec()

        findByIdAndRemove()

        Model.findByIdAndRemove(id, [options], [callback])

        clipboard.png

        刪除第0個元素

        var aIDArr = [];
        temp.find(function(err,docs){
            docs.forEach(function(item,index,arr){
                aIDArr.push(item._id);
            })
            temp.findByIdAndRemove(aIDArr[0],function(err,doc){
                //{ _id: 5972d754e6f98ec60e3dc882, name: 'huochai', age: 27 }
                console.log(doc);
            })            
        })

        clipboard.png

         類似的,該方法也不能省略回調函數,否則數據不會被刪除。當然,可以使用exec()方法來簡寫代碼

        var aIDArr = [];
        temp.find(function(err,docs){
            docs.forEach(function(item,index,arr){
                aIDArr.push(item._id);
            })
            temp.findByIdAndRemove(aIDArr[0]).exec()            
        })

        前后鉤子

         前后鉤子即pre()和post()方法,又稱為中間件,是在執行某些操作時可以執行的函數。中間件在schema上指定,類似于靜態方法或實例方法等

          可以在數據庫執行下列操作時,設置前后鉤子

            validate
            save
            remove
            count
            find
            findOne
            findOneAndRemove
            findOneAndUpdate
            insertMany
            update

        pre()

          以find()方法為例,在執行find()方法之前,執行pre()方法

        var schema = new mongoose.Schema({ age:Number, name: String,x:Number,y:Number});  
        schema.pre('find',function(next){
            console.log('我是pre方法1');
            next();
        });
        schema.pre('find',function(next){
            console.log('我是pre方法2');
            next();
        });  
        var temp = mongoose.model('temp', schema);
        temp.find(function(err,docs){
            console.log(docs[0]);
        })    
        /*
        我是pre方法1
        我是pre方法2
        { _id: 5972ed35e6f98ec60e3dc886,name: 'huochai',age: 27,x: 1,y: 2 }
        */

        post()

          post()方法并不是在執行某些操作后再去執行的方法,而在執行某些操作前最后執行的方法,post()方法里不可以使用next()

        var schema = new mongoose.Schema({ age:Number, name: String,x:Number,y:Number});  
        schema.post('find',function(docs){
            console.log('我是post方法1');
        });
        schema.post('find',function(docs){
            console.log('我是post方法2');
        });
        var temp = mongoose.model('temp', schema);
        temp.find(function(err,docs){
            console.log(docs[0]);
        }) 
        /*
        我是post方法1
        我是post方法2
        { _id: 5972ed35e6f98ec60e3dc886,name: 'huochai',age: 27,x: 1,y: 2 }
         */   

        查詢后處理

        常用的查詢后處理的方法如下所示

        sort     排序
        skip     跳過
        limit    限制
        select   顯示字段
        exect    執行
        count    計數
        distinct 去重
        var schema = new mongoose.Schema({ age:Number, name: String,x:Number,y:Number});  
        var temp = mongoose.model('temp', schema);
        temp.find(function(err,docs){
            //[ { _id: 5972ed35e6f98ec60e3dc886,name: 'huochai',age: 27,x: 1,y: 2 },
            //{ _id: 5972ed35e6f98ec60e3dc887,name: 'wang',age: 18,x: 1,y: 1 },
            //{ _id: 5972ed35e6f98ec60e3dc888, name: 'huo', age: 30, x: 2, y: 1 },
            //{ _id: 5972ed35e6f98ec60e3dc889, name: 'li', age: 20, x: 2, y: 2 } ]
            console.log(docs);
        }) 

        sort()

          按age從小到大排序

        temp.find().sort("age").exec(function(err,docs){
            //[ { _id: 5972ed35e6f98ec60e3dc887,name: 'wang',age: 18,x: 1,y: 1 },
            //{ _id: 5972ed35e6f98ec60e3dc889, name: 'li', age: 20, x: 2, y: 2 },
            //{ _id: 5972ed35e6f98ec60e3dc886,name: 'huochai',age: 27,x: 1,y: 2 },
            //{ _id: 5972ed35e6f98ec60e3dc888, name: 'huo', age: 30, x: 2, y: 1 } ]
            console.log(docs);
        }); 

          按x從小到大,age從大到小排列

        temp.find().sort("x -age").exec(function(err,docs){
            //[ { _id: 5972ed35e6f98ec60e3dc886,name: 'huochai',age: 27,x: 1,y: 2 },
            //{  _id: 5972ed35e6f98ec60e3dc887,name: 'wang',age: 18,x: 1,y: 1 },
            //{ _id: 5972ed35e6f98ec60e3dc888, name: 'huo', age: 30, x: 2, y: 1 },
            //{ _id: 5972ed35e6f98ec60e3dc889, name: 'li', age: 20, x: 2, y: 2 } ]
            console.log(docs);
        }); 

        skip()

          跳過1個,顯示其他

        temp.find().skip(1).exec(function(err,docs){
            //[ { _id: 5972ed35e6f98ec60e3dc887,name: 'wang',age: 18,x: 1,y: 1 },
            //{ _id: 5972ed35e6f98ec60e3dc888, name: 'huo', age: 30, x: 2, y: 1 },
            //{ _id: 5972ed35e6f98ec60e3dc889, name: 'li', age: 20, x: 2, y: 2 } ]
            console.log(docs);
        }); 

        limit()

          顯示2個

        temp.find().limit(2).exec(function(err,docs){
            //[ { _id: 5972ed35e6f98ec60e3dc886,name: 'huochai',age: 27,x: 1,y: 2 },
            //{ _id: 5972ed35e6f98ec60e3dc887,name: 'wang',age: 18,x: 1,y: 1 } ]
            console.log(docs);
        }); 

        select()

          顯示name、age字段,不顯示_id字段

        temp.find().select("name age -_id").exec(function(err,docs){
            //[ { name: 'huochai', age: 27 },{ name: 'wang', age: 18 },{ name: 'huo', age: 30 },{ name: 'li', age: 20 } ]
            console.log(docs);
        }); 
        temp.find().select({name:1, age:1, _id:0}).exec(function(err,docs){
            //[ { name: 'huochai', age: 27 },{ name: 'wang', age: 18 },{ name: 'huo', age: 30 },{ name: 'li', age: 20 } ]
            console.log(docs);
        }); 

          下面將以上方法結合起來使用,跳過第1個后,只顯示2個數據,按照age由大到小排序,且不顯示_id字段

        temp.find().skip(1).limit(2).sort("-age").select("-_id").exec(function(err,docs){
            //[ { name: 'huochai', age: 27, x: 1, y: 2 },
            //{ name: 'li', age: 20, x: 2, y: 2 } ]
            console.log(docs);
        }); 

        count()

          顯示集合temps中的文檔數量

        temp.find().count(function(err,count){
            console.log(count);//4
        }); 

        distinct()

          返回集合temps中的x的值

        temp.find().distinct('x',function(err,distinct){
            console.log(distinct);//[ 1, 2 ]
        }); 

        文檔驗證

        為什么需要文檔驗證呢?以一個例子作為說明,schema進行如下定義

        var schema = new mongoose.Schema({ age:Number, name: String,x:Number,y:Number});  

          如果不進行文檔驗證,保存文檔時,就可以不按照Schema設置的字段進行設置,分為以下幾種情況

          1、缺少字段的文檔可以保存成功

        var temp = mongoose.model('temp', schema);
        new temp({age:10}).save(function(err,doc){
            //{ __v: 0, age: 10, _id: 597304442b70086a1ce3cf05 }
            console.log(doc);
        }); 

          2、包含未設置的字段的文檔也可以保存成功,未設置的字段不被保存

        new temp({age:100,abc:"abc"}).save(function(err,doc){
            //{ __v: 0, age: 100, _id: 5973046a2bb57565b474f48b }
            console.log(doc);
        }); 

          3、包含字段類型與設置不同的字段的文檔也可以保存成功,不同字段類型的字段被保存為設置的字段類型

        new temp({age:true,name:10}).save(function(err,doc){
            //{ __v: 0, age: 1, name: '10', _id: 597304f7a926033060255366 }
            console.log(doc);
        }); 

          而通過文檔驗證,就可以避免以下幾種情況發生

          文檔驗證在SchemaType中定義,格式如下

        {name: {type:String, validator:value}}

          常用驗證包括以下幾種

        required: 數據必須填寫
        default: 默認值
        validate: 自定義匹配
        min: 最小值(只適用于數字)
        max: 最大值(只適用于數字)
        match: 正則匹配(只適用于字符串)
        enum:  枚舉匹配(只適用于字符串)

        required

          將age設置為必填字段,如果沒有age字段,文檔將不被保存,且出現錯誤提示

        var schema = new mongoose.Schema({ age:{type:Number,required:true}, name: String,x:Number,y:Number});  
        var temp = mongoose.model('temp', schema);
        new temp({name:"abc"}).save(function(err,doc){
            //Path `age` is required.
            console.log(err.errors['age'].message);
        }); 

        default

          設置age字段的默認值為18,如果不設置age字段,則會取默認值

        var schema = new mongoose.Schema({ age:{type:Number,default:18}, name:String,x:Number,y:Number});  
        var temp = mongoose.model('temp', schema);
        new temp({name:'a'}).save(function(err,doc){
            //{ __v: 0, name: 'a', _id: 59730d2e7a751d81582210c1, age: 18 }
            console.log(doc);
        }); 

        min | max

          將age的取值范圍設置為[0,10]。如果age取值為20,文檔將不被保存,且出現錯誤提示

        var schema = new mongoose.Schema({ age:{type:Number,min:0,max:10}, name: String,x:Number,y:Number});  
        var temp = mongoose.model('temp', schema);
        new temp({age:20}).save(function(err,doc){
            //Path `age` (20) is more than maximum allowed value (10).
            console.log(err.errors['age'].message);
        }); 

        match

          將name的match設置為必須存在'a'字符。如果name不存在'a',文檔將不被保存,且出現錯誤提示

        var schema = new mongoose.Schema({ age:Number, name:{type:String,match:/a/},x:Number,y:Number});  
        var temp = mongoose.model('temp', schema);
        new temp({name:'bbb'}).save(function(err,doc){
            //Path `name` is invalid (bbb).
            console.log(err.errors['name'].message);
        }); 

        enum

          將name的枚舉取值設置為['a','b','c'],如果name不在枚舉范圍內取值,文檔將不被保存,且出現錯誤提示

        var schema = new mongoose.Schema({ age:Number, name:{type:String,enum:['a','b','c']},x:Number,y:Number});  
        var temp = mongoose.model('temp', schema);
        new temp({name:'bbb'}).save(function(err,doc){
            //`bbb` is not a valid enum value for path `name`.
            console.log(err.errors['name'].message);
        
        }); 

        validate

          validate實際上是一個函數,函數的參數代表當前字段,返回true表示通過驗證,返回false表示未通過驗證。利用validate可以自定義任何條件。比如,定義名字name的長度必須在4個字符以上

        var validateLength = function(arg){
            if(arg.length > 4){
                return true;
            }
            return false;
        };
        var schema = new mongoose.Schema({ name:{type:String,validate:validateLength}, age:Number,x:Number,y:Number});  
        var temp = mongoose.model('temp', schema);
        new temp({name:'abc'}).save(function(err,doc){
            //Validator failed for path `name` with value `abc`
            console.log(err.errors['name'].message);
        }); 

        練習

        本節引用 mongoose的基本使用 有刪改

        連接數據庫

        編輯 test.js :

        var mongoose = require('mongoose');
        var db = mongoose.connect('mongodb://127.0.0.1:27017/test');
        db.connection.on('error', function(error){
          console.log('數據庫test連接失?。? + error);
        });
        db.connection.on('open', function(){
          console.log('數據庫test連接成功');
        });

        接著先打開一個 iTerm2 終端,開啟 mongodb 服務:

        mongod

        再打開另一個 iTerm2 終端,運行 test.js:

        node test.js
        //成功后便會輸出:數據庫test連接成功

        Schema/Model/Entity

        沒有比文檔更詳細的了:http://mongoosejs.com/docs/gu...

        Schema:數據庫集合的結構對象。
        Model :由Schema構造而成,可操作數據庫。
        Entity:由Model創建的實體,可操作數據庫。

        看完文檔后,再看看下面一段代碼配合理解一下:

        var mongoose = require("mongoose");
        var db = mongoose.connect("mongodb://127.0.0.1:27017/test");
        // var testModel = db.model('test1', testSchema); // 集合名稱;集合的結構對象
        var TestSchema = new mongoose.Schema({
            name : { type:String },
            age  : { type:Number, default:0 },
            email: { type:String },
            time : { type:Date, default:Date.now }
        });
        var TestModel = db.model("test1", TestSchema );
        var TestEntity = new TestModel({
            name : "helloworld",
            age  : 28,
            email: "helloworld@qq.com"
        });
        TestEntity.save(function(error,doc){
          if(error){
             console.log("error :" + error);
          }else{
             console.log(doc);
          }
        });

        model 數據插入

        在前面的數據庫連接成功的前提下,我們在數據庫 test 下新建一個集合 test1 、并往里面插入保存一組數據:

        var testSchema = new mongoose.Schema({
          name: {type: String},
          age: {type: Number, default: 0},
          email: {type: String},
          time: {type: Date, default: Date.now}
        });
        var testModel = db.model('test1', testSchema); // 集合名稱;集合的結構對象
        // Document文檔(關聯數組式的對象) < Collection集合 < 數據庫
        // 插入保存一段數據
        testModel.create([
          {name: "test1", age: 8},
          {name: "test2", age: 18},
          {name: "test3", age: 28},
          {name: "test4", age: 38},
          {name: "test5", age: 48},
          {name: "test6", age: 58, email:"tttt@qq.com"},
          {name: "test7", age: 68, email:"ssss@qq.com"},
          {name: "test8", age: 18},
          {name: "test9", age: 18, email:"rrrr@qq.com"},
          {name: "test10",age: 18}
        ], function (error, docs) {
          if(error) {
            console.log(error);
          } else {
            console.log('save ok');
            console.log(docs);
          }
        });

        find 數據查詢

        mongoose 提供了find、findOne、和findById方法用于文檔查詢。
        基本語法:

        model.find(Conditions,fields,options,callback(err, doc));
        // Conditions: 查詢條件
        // fields: 返回的字段
        // options: 游標(sort,limit)
        // callback: 回調函數,參數doc為查詢出來的結果

        條件查詢的基礎:

        $lt (小于<)
        $lte (小于等于<=)
        $gt (大于>)
        $gte (大于等于>=)
        $ne (不等于,不包含!=)
        $in (包含)
        $or (查詢多個鍵值的任意給定值)
        $exists (判斷某些屬性是否存在)
        $all (全部)

        具體的一些實例,代碼里已有詳細注釋:

        // find(Conditions,fields,callback);
        // 省略或為空、返回所有記錄;只包含name,age字段,去掉默認的_id字段;執行回調函數
        testModel.find({}, {name:1, age:1, _id:0}, function(err, docs){
          if (err) {
            console.log('查詢出錯:' + err);
          } else {
            console.log('{}查詢結果為:');
            console.log(docs);
          }
        });
        ----
        {}查詢結果為:
        [ { name: 'test3', age: 28 },
          { name: 'test2', age: 18 },
          { name: 'test1', age: 8 },
          { name: 'test6', age: 58 },
          { name: 'test4', age: 38 },
          { name: 'test7', age: 68 },
          { name: 'test8', age: 18 },
          { name: 'test9', age: 18 },
          { name: 'test5', age: 48 },
          { name: 'test10', age: 18 } ]
        ----
        // 查詢age大于等于28,小于等于48
        testModel.find({age: {$gte: 28, $lte: 48}}, {name:1, age:1, _id:0}, function(err, docs){
          if (err) {
            console.log('查詢出錯:' + err);
          } else {
            console.log('$gte,$lte查詢結果為:');
            console.log(docs);
          }
        });
        ----
        $gte,$lte查詢結果為:
        [ { name: 'test3', age: 28 },
          { name: 'test4', age: 38 },
          { name: 'test5', age: 48 } ]
        ----
        // 查詢age為58、68的2條數據
        testModel.find({age: {$in: [58, 68]}}, {name:1, age:1, _id:0}, function(err, docs){
          if (err) {
            console.log('查詢出錯:' + err);
          } else {
            console.log('$in查詢結果為:');
            console.log(docs);
          }
        });
        ----
        $in查詢結果為:
        [ { name: 'test6', age: 58 }, { name: 'test7', age: 68 } ]
        ----
        // 查詢name為test3、或者age為18的全部數據
        testModel.find({$or: [{name: 'test3'}, {age: 18}]}, {name:1, age:1, _id:0}, function(err, docs){
          if (err) {
            console.log('查詢出錯:' + err);
          } else {
            console.log('$or查詢結果為:');
            console.log(docs);
          }
        });
        ----
        $or查詢結果為:
        [ { name: 'test3', age: 28 },
          { name: 'test2', age: 18 },
          { name: 'test8', age: 18 },
          { name: 'test9', age: 18 },
          { name: 'test10', age: 18 } ]
        ----
        
        // step3:游標查詢
        // 查詢name為test3、或者age為18的全部數據;但限制只查詢2條數據
        testModel.find({$or: [{name: 'test3'}, {age: 18}]}, {name:1, age:1, _id:0}, {limit: 2}, function(err, docs){
          if (err) {
            console.log('查詢出錯:' + err);
          } else {
            console.log('limit查詢結果為:');
            console.log(docs);
          }
        });
        ----
        limit查詢結果為:
        [ { name: 'test3', age: 28 }, { name: 'test2', age: 18 } ]
        ----
        
        //查詢age大于等于28,小于等于48;降序輸出
        testModel.find({age: {$gte: 28, $lte: 48}}, {name:1, age:1, _id:0}, {sort: {age: -1}}, function(err, docs){
          if (err) {
            console.log('查詢出錯:' + err);
          } else {
            console.log('sort查詢結果為:');
            console.log(docs);
          }
        });
        ----
        sort查詢結果為:
        [ { name: 'test5', age: 48 },
          { name: 'test4', age: 38 },
          { name: 'test3', age: 28 } ]
        ----

        update 數據更新

        基本使用:model.update(查詢條件,更新對象,callback);

        var conditions = {name: 'test1'};
        var update = {$set: {age: 11 }};
        testModel.update(conditions, update, function(error){
          if(error) {
            console.log(error);
          } else {
            console.log('Update success!');
            testModel.find({name: 'test1'}, {name:1, age:1, _id:0}, function(err, docs){
              if (err) {
                console.log('查詢出錯:' + err);
              } else {
                console.log('更新test1后的查詢結果為:');
                console.log(docs);  
                // 更新test_update后的查詢結果為空數組:[ ];
                // 更新test1后的查詢結果為: [ { name: 'test1', age: 11 } ]
                // 只能更新本來已存在的數據
              }
            });
          }
        ---
        Update success!
        更新test1后的查詢結果為:
        [ { name: 'test1', age: 11 } ]
        ---

        remove 數據刪除

        基本使用:model.remove(查詢條件,callback);

        var conditions = {name: 'test2'};
        testModel.remove(conditions, function(error){
          if(error) {
            console.log(error);
          } else {
            console.log('Delete success!');
            testModel.find({name: 'test2'}, {name:1, age:1, _id:0}, function(err, docs){
              if (err) {
                console.log('查詢出錯:' + err);
              } else {
                console.log('刪除test2后的查詢結果為:');
                console.log(docs);  // 刪除test2后的查詢結果為空數組:[ ];
              }
            });
          }
        });
        ----
        Delete success!
        刪除test2后的查詢結果為:
        []
        ----

        參考引用

        1. http://mongoosejs.com
        2. Mongoose簡要API
        3. Nodejs學習筆記(十四)— Mongoose介紹和入門
        4. Mongoose基礎入門
        查看原文

        贊 81 收藏 66 評論 2

        旅圖灬 提出了問題 · 2月20日

        Failed to load resource: net::ERR_NETWORK_CHANGED,是什么原因導致的報錯?

        圖片資源加載的時候有時候會遇 Failed to load resource: net::ERR_NETWORK_CHANGED,導致我這邊沒有辦法判斷圖片是否加載完成,有大神知道是什么原因導致的報錯么

        關注 2 回答 1

        旅圖灬 關注了問題 · 2月20日

        Failed to load resource: net::ERR_NETWORK_CHANGED,這是什么錯誤?

        Failed to load resource: net::ERR_NETWORK_CHANGED,我用ajax請求數據,并發量比較大,然后就會報這個錯

        關注 3 回答 1

        旅圖灬 發布了文章 · 1月11日

        Error: No files matching the pattern "/xxx/xxx/..." were found.

        使用.stylelintignore添加忽略文件校驗,在lint-staged執行校驗規范時,報錯

        ? stylelint --fix:
        Error: No files matching the pattern "/Users/lyc/Desktop/tal/monkey-wukong-wap/src/pages/reportActivity/assets/iconfont/iconfont.css" were found.
            at /Users/lyc/Desktop/tal/monkey-wukong-wap/node_modules/stylelint/lib/standalone.js:212:12
            at processTicksAndRejections (internal/process/task_queues.js:97:5)

        解決方案:lint-staged stylelint添加--allow-empty-input

        "lint-staged": {
          "*.{js,vue}": [
            "vue-cli-service lint"
          ],
          "*.{less,vue}": [
            "stylelint --allow-empty-input"
          ]
        }

        最終在 https://github.com/stylelint/... 找到解決方案,但是仍不是特別清楚具體原因以及什么時候添加這個--allow-empty-input屬性。

        查看原文

        贊 0 收藏 0 評論 0

        旅圖灬 回答了問題 · 1月8日

        解決eslint 校驗輸出報錯,有沒有大佬遇到過

        問題解決了。。。是因為eslint版本 跟 airbnb 版本不兼容導致的,將 eslint升為@lasted就可以了

        關注 2 回答 2

        旅圖灬 提出了問題 · 1月8日

        解決eslint 校驗輸出報錯,有沒有大佬遇到過

        Configuration for rule "camelcase" is invalid:     
        Value {"properties":"never","ignoreDestructuring":false} 
        should NOT have additional properties.
        

        直接導致eslint校驗失效了

        image.png

        關注 2 回答 2

        認證與成就

        • 獲得 137 次點贊
        • 獲得 75 枚徽章 獲得 4 枚金徽章, 獲得 28 枚銀徽章, 獲得 43 枚銅徽章

        擅長技能
        編輯

        開源項目 & 著作
        編輯

        (??? )
        暫時沒有

        注冊于 2016-02-25
        個人主頁被 3.6k 人瀏覽

        一本到在线是免费观看_亚洲2020天天堂在线观看_国产欧美亚洲精品第一页_最好看的2018中文字幕