pbootcms网站模板|日韩1区2区|织梦模板||网站源码|日韩1区2区|jquery建站特效-html5模板网

<tfoot id='uJ8IG'></tfoot>
  • <i id='uJ8IG'><tr id='uJ8IG'><dt id='uJ8IG'><q id='uJ8IG'><span id='uJ8IG'><b id='uJ8IG'><form id='uJ8IG'><ins id='uJ8IG'></ins><ul id='uJ8IG'></ul><sub id='uJ8IG'></sub></form><legend id='uJ8IG'></legend><bdo id='uJ8IG'><pre id='uJ8IG'><center id='uJ8IG'></center></pre></bdo></b><th id='uJ8IG'></th></span></q></dt></tr></i><div class="xqwnera" id='uJ8IG'><tfoot id='uJ8IG'></tfoot><dl id='uJ8IG'><fieldset id='uJ8IG'></fieldset></dl></div>
  • <small id='uJ8IG'></small><noframes id='uJ8IG'>

      • <bdo id='uJ8IG'></bdo><ul id='uJ8IG'></ul>
    1. <legend id='uJ8IG'><style id='uJ8IG'><dir id='uJ8IG'><q id='uJ8IG'></q></dir></style></legend>

        Mongoose 多對多

        Many to Many with Mongoose(Mongoose 多對多)
        <legend id='maiJo'><style id='maiJo'><dir id='maiJo'><q id='maiJo'></q></dir></style></legend>

          <tbody id='maiJo'></tbody>

            <tfoot id='maiJo'></tfoot>

                <i id='maiJo'><tr id='maiJo'><dt id='maiJo'><q id='maiJo'><span id='maiJo'><b id='maiJo'><form id='maiJo'><ins id='maiJo'></ins><ul id='maiJo'></ul><sub id='maiJo'></sub></form><legend id='maiJo'></legend><bdo id='maiJo'><pre id='maiJo'><center id='maiJo'></center></pre></bdo></b><th id='maiJo'></th></span></q></dt></tr></i><div class="hzrum0c" id='maiJo'><tfoot id='maiJo'></tfoot><dl id='maiJo'><fieldset id='maiJo'></fieldset></dl></div>

                <small id='maiJo'></small><noframes id='maiJo'>

                  <bdo id='maiJo'></bdo><ul id='maiJo'></ul>

                • 本文介紹了Mongoose 多對多的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧!

                  問題描述

                  我有兩個模型:

                  Item.js

                  const mongoose = require('mongoose');
                  
                  const itemSchema = new mongoose.Schema({
                     name: String,
                     stores: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Store' }]
                  });
                  
                  const Item = mongoose.model('Item', itemSchema);
                  
                  module.exports = Item;
                  

                  Store.js

                  const mongoose = require('mongoose');
                  
                  const storeSchema = new mongoose.Schema({
                     name: String,
                     items: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Item' }]
                  });
                  
                  const Store = mongoose.model('Store', storeSchema);
                  
                  module.exports = Store;
                  

                  還有一個 seed.js 文件:

                  const faker = require('faker');
                  const Store = require('./models/Store');
                  const Item = require('./models/Item');
                  
                  console.log('Seeding..');
                  
                  let item = new Item({
                     name: faker.name.findName() + " Item"
                  });
                  
                  item.save((err) => {
                     if (err) return;
                  
                     let store = new Store({
                        name: faker.name.findName() + " Store"
                     });
                     store.items.push(item);
                     store.save((err) => {
                        if (err) return;
                     })
                  });
                  

                  store 與包含 1 個 itemitems 數(shù)組一起保存.item 但是沒有stores.我錯過了什么?如何自動更新 MongoDB/Mongoose 中的多對多關(guān)系?我習(xí)慣了 Rails,一切都是自動完成的.

                  The store is saved with the items array containing 1 item. The item though, doesn't have stores. What am I missing? How to automatically update the many-to-many relationships in MongoDB/Mongoose? I was used to Rails and everything was done automatically.

                  推薦答案

                  您目前遇到的問題是您將引用保存在一個模型中,但您沒有將其保存在另一個模型中.MongoDB中沒有自動參照完整性",關(guān)系"這樣的概念實(shí)際上是手動"的事情,實(shí)際上 .populate() 的情況實(shí)際上是一堆額外的查詢以檢索引用的信息.這里沒有魔法".

                  The problem you presently have is that you saved the reference in one model but you did not save it in the other. There is no "automatic referential integrity" in MongoDB, and such concept of "relations" are really a "manual" affair, and in fact the case with .populate() is actually a whole bunch of additional queries in order to retrieve the referenced information. No "magic" here.

                  正確處理多對多"歸結(jié)為三個選項:

                  Correct handling of "many to many" comes down to three options:

                  按照您當(dāng)前的設(shè)計,您缺少的部分是將引用存儲在兩個"相關(guān)項目上.如需展示清單:

                  Following your current design, the parts you are missing is storing the referenced on "both" the related items. For a listing to demonstrate:

                  const { Schema } = mongoose = require('mongoose');
                  
                  mongoose.Promise = global.Promise;
                  mongoose.set('debug',true);
                  mongoose.set('useFindAndModify', false);
                  mongoose.set('useCreateIndex', true);
                  
                  const uri = 'mongodb://localhost:27017/manydemo',
                        options = { useNewUrlParser: true };
                  
                  const itemSchema = new Schema({
                    name: String,
                    stores: [{ type: Schema.Types.ObjectId, ref: 'Store' }]
                  });
                  
                  const storeSchema = new Schema({
                    name: String,
                    items: [{ type: Schema.Types.ObjectId, ref: 'Item' }]
                  });
                  
                  const Item = mongoose.model('Item', itemSchema);
                  const Store = mongoose.model('Store', storeSchema);
                  
                  
                  const log = data => console.log(JSON.stringify(data,undefined,2))
                  
                  (async function() {
                  
                    try {
                  
                      const conn = await mongoose.connect(uri,options);
                  
                      // Clean data
                      await Promise.all(
                        Object.entries(conn.models).map(([k,m]) => m.deleteMany() )
                      );
                  
                  
                      // Create some instances
                      let [toothpaste,brush] = ['toothpaste','brush'].map(
                        name => new Item({ name })
                      );
                  
                      let [billsStore,tedsStore] = ['Bills','Teds'].map(
                        name => new Store({ name })
                      );
                  
                      // Add items to stores
                      [billsStore,tedsStore].forEach( store => {
                        store.items.push(toothpaste);   // add toothpaste to store
                        toothpaste.stores.push(store);  // add store to toothpaste
                      });
                  
                      // Brush is only in billsStore
                      billsStore.items.push(brush);
                      brush.stores.push(billsStore);
                  
                      // Save everything
                      await Promise.all(
                        [toothpaste,brush,billsStore,tedsStore].map( m => m.save() )
                      );
                  
                      // Show stores
                      let stores = await Store.find().populate('items','-stores');
                      log(stores);
                  
                      // Show items
                      let items = await Item.find().populate('stores','-items');
                      log(items);
                  
                    } catch(e) {
                      console.error(e);
                    } finally {
                      mongoose.disconnect();
                    }
                  
                  })();
                  

                  這將創(chuàng)建項目"集合:

                  {
                      "_id" : ObjectId("59ab96d9c079220dd8eec428"),
                      "name" : "toothpaste",
                      "stores" : [
                              ObjectId("59ab96d9c079220dd8eec42a"),
                              ObjectId("59ab96d9c079220dd8eec42b")
                      ],
                      "__v" : 0
                  }
                  {
                      "_id" : ObjectId("59ab96d9c079220dd8eec429"),
                      "name" : "brush",
                      "stores" : [
                              ObjectId("59ab96d9c079220dd8eec42a")
                      ],
                      "__v" : 0
                  }
                  

                  還有商店"集合:

                  {
                      "_id" : ObjectId("59ab96d9c079220dd8eec42a"),
                      "name" : "Bills",
                      "items" : [
                              ObjectId("59ab96d9c079220dd8eec428"),
                              ObjectId("59ab96d9c079220dd8eec429")
                      ],
                      "__v" : 0
                  }
                  {
                      "_id" : ObjectId("59ab96d9c079220dd8eec42b"),
                      "name" : "Teds",
                      "items" : [
                              ObjectId("59ab96d9c079220dd8eec428")
                      ],
                      "__v" : 0
                  }
                  

                  并產(chǎn)生整體輸出,例如:

                  And produces overall output such as:

                  Mongoose: items.deleteMany({}, {})
                  Mongoose: stores.deleteMany({}, {})
                  Mongoose: items.insertOne({ name: 'toothpaste', _id: ObjectId("59ab96d9c079220dd8eec428"), stores: [ ObjectId("59ab96d9c079220dd8eec42a"), ObjectId("59ab96d9c079220dd8eec42b") ], __v: 0 })
                  Mongoose: items.insertOne({ name: 'brush', _id: ObjectId("59ab96d9c079220dd8eec429"), stores: [ ObjectId("59ab96d9c079220dd8eec42a") ], __v: 0 })
                  Mongoose: stores.insertOne({ name: 'Bills', _id: ObjectId("59ab96d9c079220dd8eec42a"), items: [ ObjectId("59ab96d9c079220dd8eec428"), ObjectId("59ab96d9c079220dd8eec429") ], __v: 0 })
                  Mongoose: stores.insertOne({ name: 'Teds', _id: ObjectId("59ab96d9c079220dd8eec42b"), items: [ ObjectId("59ab96d9c079220dd8eec428") ], __v: 0 })
                  Mongoose: stores.find({}, { fields: {} })
                  Mongoose: items.find({ _id: { '$in': [ ObjectId("59ab96d9c079220dd8eec428"), ObjectId("59ab96d9c079220dd8eec429") ] } }, { fields: { stores: 0 } })
                  [
                    {
                      "_id": "59ab96d9c079220dd8eec42a",
                      "name": "Bills",
                      "__v": 0,
                      "items": [
                        {
                          "_id": "59ab96d9c079220dd8eec428",
                          "name": "toothpaste",
                          "__v": 0
                        },
                        {
                          "_id": "59ab96d9c079220dd8eec429",
                          "name": "brush",
                          "__v": 0
                        }
                      ]
                    },
                    {
                      "_id": "59ab96d9c079220dd8eec42b",
                      "name": "Teds",
                      "__v": 0,
                      "items": [
                        {
                          "_id": "59ab96d9c079220dd8eec428",
                          "name": "toothpaste",
                          "__v": 0
                        }
                      ]
                    }
                  ]
                  Mongoose: items.find({}, { fields: {} })
                  Mongoose: stores.find({ _id: { '$in': [ ObjectId("59ab96d9c079220dd8eec42a"), ObjectId("59ab96d9c079220dd8eec42b") ] } }, { fields: { items: 0 } })
                  [
                    {
                      "_id": "59ab96d9c079220dd8eec428",
                      "name": "toothpaste",
                      "__v": 0,
                      "stores": [
                        {
                          "_id": "59ab96d9c079220dd8eec42a",
                          "name": "Bills",
                          "__v": 0
                        },
                        {
                          "_id": "59ab96d9c079220dd8eec42b",
                          "name": "Teds",
                          "__v": 0
                        }
                      ]
                    },
                    {
                      "_id": "59ab96d9c079220dd8eec429",
                      "name": "brush",
                      "__v": 0,
                      "stores": [
                        {
                          "_id": "59ab96d9c079220dd8eec42a",
                          "name": "Bills",
                          "__v": 0
                        }
                      ]
                    }
                  ]
                  

                  關(guān)鍵點(diǎn)在于您實(shí)際上將參考數(shù)據(jù)添加到存在關(guān)系的每個集合中的每個文檔中.此處存在的數(shù)組"用于存儲這些引用并查找"相關(guān)集合中的結(jié)果,并將它們替換為存儲在那里的對象數(shù)據(jù).

                  The key points being that you actually add the reference data to each document in each collection where a relationship exists. The "arrays" present are used here to store those references and "lookup" the results from the related collection and replace them with the object data that was stored there.

                  注意以下部分:

                  // Add items to stores
                  [billsStore,tedsStore].forEach( store => {
                    store.items.push(toothpaste);   // add toothpaste to store
                    toothpaste.stores.push(store);  // add store to toothpaste
                  });
                  

                  因為這意味著我們不僅將 toothpaste 添加到每個商店的 "items" 數(shù)組中,而且還添加了每個 "store"toothpaste 項的 "stores" 數(shù)組.這樣做是為了可以從任一方向查詢關(guān)系.如果您只想要來自商店的商品"并且從不來自商品的商店",那么您根本不需要將關(guān)系數(shù)據(jù)存儲在商品"條目上.

                  Because that means not only are we adding the toothpaste to the "items" array in each store, but we are also adding each "store" to the "stores" array of the toothpaste item. This is done so the relationships can work being queried from either direction. If you only wanted "items from stores" and never "stores from items", then you would not need to store the relation data on the "item" entries at all.

                  這本質(zhì)上是經(jīng)典的多對多"關(guān)系.這里不是直接定義兩個集合之間的關(guān)系,而是另一個集合(表)存儲有關(guān)哪個項目與哪個商店相關(guān)的詳細(xì)信息.

                  This is essentially the classic "many to many" relation. Where instead of directly defining relationships between the two collections, there is another collection ( table ) that stores the details about which item is related to which store.

                  作為完整列表:

                  const { Schema } = mongoose = require('mongoose');
                  
                  mongoose.Promise = global.Promise;
                  mongoose.set('debug',true);
                  mongoose.set('useFindAndModify', false);
                  mongoose.set('useCreateIndex', true);
                  
                  const uri = 'mongodb://localhost:27017/manydemo',
                        options = { useNewUrlParser: true };
                  
                  const itemSchema = new Schema({
                    name: String,
                  },{
                   toJSON: { virtuals: true }
                  });
                  
                  itemSchema.virtual('stores', {
                    ref: 'StoreItem',
                    localField: '_id',
                    foreignField: 'itemId'
                  });
                  
                  const storeSchema = new Schema({
                    name: String,
                  },{
                   toJSON: { virtuals: true }
                  });
                  
                  storeSchema.virtual('items', {
                    ref: 'StoreItem',
                    localField: '_id',
                    foreignField: 'storeId'
                  });
                  
                  const storeItemSchema = new Schema({
                    storeId: { type: Schema.Types.ObjectId, ref: 'Store', required: true },
                    itemId: { type: Schema.Types.ObjectId, ref: 'Item', required: true }
                  });
                  
                  const Item = mongoose.model('Item', itemSchema);
                  const Store = mongoose.model('Store', storeSchema);
                  const StoreItem = mongoose.model('StoreItem', storeItemSchema);
                  
                  const log = data => console.log(JSON.stringify(data,undefined,2));
                  
                  (async function() {
                  
                    try {
                  
                      const conn = await mongoose.connect(uri,options);
                  
                      // Clean data
                      await Promise.all(
                        Object.entries(conn.models).map(([k,m]) => m.deleteMany() )
                      );
                  
                      // Create some instances
                      let [toothpaste,brush] = await Item.insertMany(
                        ['toothpaste','brush'].map( name => ({ name }) )
                      );
                      let [billsStore,tedsStore] = await Store.insertMany(
                        ['Bills','Teds'].map( name => ({ name }) )
                      );
                  
                      // Add toothpaste to both stores
                      for( let store of [billsStore,tedsStore] ) {
                        await StoreItem.update(
                          { storeId: store._id, itemId: toothpaste._id },
                          { },
                          { 'upsert': true }
                        );
                      }
                  
                      // Add brush to billsStore
                      await StoreItem.update(
                        { storeId: billsStore._id, itemId: brush._id },
                        {},
                        { 'upsert': true }
                      );
                  
                      // Show stores
                      let stores = await Store.find().populate({
                        path: 'items',
                        populate: { path: 'itemId' }
                      });
                      log(stores);
                  
                      // Show Items
                      let items = await Item.find().populate({
                        path: 'stores',
                        populate: { path: 'storeId' }
                      });
                      log(items);
                  
                  
                    } catch(e) {
                      console.error(e);
                    } finally {
                      mongoose.disconnect();
                    }
                  
                  })();
                  

                  關(guān)系現(xiàn)在在它們自己的集合中,所以數(shù)據(jù)現(xiàn)在顯示不同,對于項目":

                  The relations are now in their own collection, so the data now appears differently, for "items":

                  {
                      "_id" : ObjectId("59ab996166d5cc0e0d164d74"),
                      "__v" : 0,
                      "name" : "toothpaste"
                  }
                  {
                      "_id" : ObjectId("59ab996166d5cc0e0d164d75"),
                      "__v" : 0,
                      "name" : "brush"
                  }
                  

                  還有商店":

                  {
                      "_id" : ObjectId("59ab996166d5cc0e0d164d76"),
                      "__v" : 0,
                      "name" : "Bills"
                  }
                  {
                      "_id" : ObjectId("59ab996166d5cc0e0d164d77"),
                      "__v" : 0,
                      "name" : "Teds"
                  }
                  

                  現(xiàn)在是映射關(guān)系的storeitems":

                  And now for "storeitems" which maps the relations:

                  {
                      "_id" : ObjectId("59ab996179e41cc54405b72b"),
                      "itemId" : ObjectId("59ab996166d5cc0e0d164d74"),
                      "storeId" : ObjectId("59ab996166d5cc0e0d164d76"),
                      "__v" : 0
                  }
                  {
                      "_id" : ObjectId("59ab996179e41cc54405b72d"),
                      "itemId" : ObjectId("59ab996166d5cc0e0d164d74"),
                      "storeId" : ObjectId("59ab996166d5cc0e0d164d77"),
                      "__v" : 0
                  }
                  {
                      "_id" : ObjectId("59ab996179e41cc54405b72f"),
                      "itemId" : ObjectId("59ab996166d5cc0e0d164d75"),
                      "storeId" : ObjectId("59ab996166d5cc0e0d164d76"),
                      "__v" : 0
                  }
                  

                  完整輸出如下:

                  Mongoose: items.deleteMany({}, {})
                  Mongoose: stores.deleteMany({}, {})
                  Mongoose: storeitems.deleteMany({}, {})
                  Mongoose: items.insertMany([ { __v: 0, name: 'toothpaste', _id: 59ab996166d5cc0e0d164d74 }, { __v: 0, name: 'brush', _id: 59ab996166d5cc0e0d164d75 } ])
                  Mongoose: stores.insertMany([ { __v: 0, name: 'Bills', _id: 59ab996166d5cc0e0d164d76 }, { __v: 0, name: 'Teds', _id: 59ab996166d5cc0e0d164d77 } ])
                  Mongoose: storeitems.update({ itemId: ObjectId("59ab996166d5cc0e0d164d74"), storeId: ObjectId("59ab996166d5cc0e0d164d76") }, { '$setOnInsert': { __v: 0 } }, { upsert: true })
                  Mongoose: storeitems.update({ itemId: ObjectId("59ab996166d5cc0e0d164d74"), storeId: ObjectId("59ab996166d5cc0e0d164d77") }, { '$setOnInsert': { __v: 0 } }, { upsert: true })
                  Mongoose: storeitems.update({ itemId: ObjectId("59ab996166d5cc0e0d164d75"), storeId: ObjectId("59ab996166d5cc0e0d164d76") }, { '$setOnInsert': { __v: 0 } }, { upsert: true })
                  Mongoose: stores.find({}, { fields: {} })
                  Mongoose: storeitems.find({ storeId: { '$in': [ ObjectId("59ab996166d5cc0e0d164d76"), ObjectId("59ab996166d5cc0e0d164d77") ] } }, { fields: {} })
                  Mongoose: items.find({ _id: { '$in': [ ObjectId("59ab996166d5cc0e0d164d74"), ObjectId("59ab996166d5cc0e0d164d75") ] } }, { fields: {} })
                  [
                    {
                      "_id": "59ab996166d5cc0e0d164d76",
                      "__v": 0,
                      "name": "Bills",
                      "items": [
                        {
                          "_id": "59ab996179e41cc54405b72b",
                          "itemId": {
                            "_id": "59ab996166d5cc0e0d164d74",
                            "__v": 0,
                            "name": "toothpaste",
                            "stores": null,
                            "id": "59ab996166d5cc0e0d164d74"
                          },
                          "storeId": "59ab996166d5cc0e0d164d76",
                          "__v": 0
                        },
                        {
                          "_id": "59ab996179e41cc54405b72f",
                          "itemId": {
                            "_id": "59ab996166d5cc0e0d164d75",
                            "__v": 0,
                            "name": "brush",
                            "stores": null,
                            "id": "59ab996166d5cc0e0d164d75"
                          },
                          "storeId": "59ab996166d5cc0e0d164d76",
                          "__v": 0
                        }
                      ],
                      "id": "59ab996166d5cc0e0d164d76"
                    },
                    {
                      "_id": "59ab996166d5cc0e0d164d77",
                      "__v": 0,
                      "name": "Teds",
                      "items": [
                        {
                          "_id": "59ab996179e41cc54405b72d",
                          "itemId": {
                            "_id": "59ab996166d5cc0e0d164d74",
                            "__v": 0,
                            "name": "toothpaste",
                            "stores": null,
                            "id": "59ab996166d5cc0e0d164d74"
                          },
                          "storeId": "59ab996166d5cc0e0d164d77",
                          "__v": 0
                        }
                      ],
                      "id": "59ab996166d5cc0e0d164d77"
                    }
                  ]
                  Mongoose: items.find({}, { fields: {} })
                  Mongoose: storeitems.find({ itemId: { '$in': [ ObjectId("59ab996166d5cc0e0d164d74"), ObjectId("59ab996166d5cc0e0d164d75") ] } }, { fields: {} })
                  Mongoose: stores.find({ _id: { '$in': [ ObjectId("59ab996166d5cc0e0d164d76"), ObjectId("59ab996166d5cc0e0d164d77") ] } }, { fields: {} })
                  [
                    {
                      "_id": "59ab996166d5cc0e0d164d74",
                      "__v": 0,
                      "name": "toothpaste",
                      "stores": [
                        {
                          "_id": "59ab996179e41cc54405b72b",
                          "itemId": "59ab996166d5cc0e0d164d74",
                          "storeId": {
                            "_id": "59ab996166d5cc0e0d164d76",
                            "__v": 0,
                            "name": "Bills",
                            "items": null,
                            "id": "59ab996166d5cc0e0d164d76"
                          },
                          "__v": 0
                        },
                        {
                          "_id": "59ab996179e41cc54405b72d",
                          "itemId": "59ab996166d5cc0e0d164d74",
                          "storeId": {
                            "_id": "59ab996166d5cc0e0d164d77",
                            "__v": 0,
                            "name": "Teds",
                            "items": null,
                            "id": "59ab996166d5cc0e0d164d77"
                          },
                          "__v": 0
                        }
                      ],
                      "id": "59ab996166d5cc0e0d164d74"
                    },
                    {
                      "_id": "59ab996166d5cc0e0d164d75",
                      "__v": 0,
                      "name": "brush",
                      "stores": [
                        {
                          "_id": "59ab996179e41cc54405b72f",
                          "itemId": "59ab996166d5cc0e0d164d75",
                          "storeId": {
                            "_id": "59ab996166d5cc0e0d164d76",
                            "__v": 0,
                            "name": "Bills",
                            "items": null,
                            "id": "59ab996166d5cc0e0d164d76"
                          },
                          "__v": 0
                        }
                      ],
                      "id": "59ab996166d5cc0e0d164d75"
                    }
                  ]
                  

                  由于關(guān)系現(xiàn)在映射到單獨(dú)的集合中,因此這里有一些更改.值得注意的是,我們希望在集合上定義一個虛擬"字段,該字段不再具有固定的項目數(shù)組.所以你添加一個,如圖所示:

                  Since the relations are now mapped in a separate collection there are a couple of changes here. Notably we want to define a "virtual" field on the collection that no longer has a fixed array of items. So you add one as is shown:

                  const itemSchema = new Schema({
                    name: String,
                  },{
                   toJSON: { virtuals: true }
                  });
                  
                  itemSchema.virtual('stores', {
                    ref: 'StoreItem',
                    localField: '_id',
                    foreignField: 'itemId'
                  });
                  

                  您使用它的 localFieldforeignField 映射分配虛擬字段,以便隨后的 .populate() 調(diào)用知道要使用什么.

                  You assign the virtual field with it's localField and foreignField mappings so the subsequent .populate() call knows what to use.

                  中間集合有一個相當(dāng)標(biāo)準(zhǔn)的定義:

                  The intermediary collection has a fairly standard definition:

                  const storeItemSchema = new Schema({
                    storeId: { type: Schema.Types.ObjectId, ref: 'Store', required: true },
                    itemId: { type: Schema.Types.ObjectId, ref: 'Item', required: true }
                  });
                  

                  我們不是將新項目推送"到數(shù)組中,而是將它們添加到這個新集合中.一種合理的方法是僅在此組合不存在時才使用upserts"創(chuàng)建新條目:

                  And instead of "pushing" new items onto arrays, we instead add them to this new collection. A reasonable method for this is using "upserts" to create a new entry only when this combination does not exist:

                  // Add toothpaste to both stores
                  for( let store of [billsStore,tedsStore] ) {
                    await StoreItem.update(
                      { storeId: store._id, itemId: toothpaste._id },
                      { },
                      { 'upsert': true }
                    );
                  }
                  

                  這是一種非常簡單的方法,它僅使用查詢中提供的兩個鍵創(chuàng)建一個新文檔,其中一個未找到,或者本質(zhì)上嘗試在匹配時更新同一個文檔,在這種情況下使用nothing".因此,現(xiàn)有的匹配最終會成為無操作",這是需要做的事情.或者,您可以簡單地 .insertOne() 忽略重復(fù)鍵錯誤.隨心所欲.

                  It's a pretty simple method that merely creates a new document with the two keys supplied in the query where one was not found, or essentially tries to update the same document when matched, and with "nothing" in this case. So existing matches just end up as a "no-op", which is the desired thing to do. Alternately you could simply .insertOne() an ignore duplicate key errors. Whatever takes your fancy.

                  實(shí)際上查詢這些相關(guān)"數(shù)據(jù)的工作方式又略有不同.因為涉及到另一個集合,我們調(diào)用 .populate() 的方式認(rèn)為它也需要查找"其他檢索到的屬性上的關(guān)系.所以你有這樣的電話:

                  Actually querying this "related" data works a little differently again. Because there is another collection involved, we call .populate() in a way that considers it needs to "lookup" the relation on other retrieved property as well. So you have calls like this:

                   // Show stores
                    let stores = await Store.find().populate({
                      path: 'items',
                      populate: { path: 'itemId' }
                    });
                    log(stores);
                  

                  清單 3 - 在服務(wù)器上使用 Modern Features 來實(shí)現(xiàn)

                  因此,根據(jù)所采用的方法,使用數(shù)組或中間集合來存儲關(guān)系數(shù)據(jù)作為文檔中不斷增長的數(shù)組"的替代方法,那么您應(yīng)該注意的顯而易見的事情是 .使用的 populate() 調(diào)用實(shí)際上是對 MongoDB 進(jìn)行額外的查詢,并在單獨(dú)的請求中通過網(wǎng)絡(luò)拉取這些文檔.

                  Listing 3 - Use Modern Features to do it on the server

                  So depending on which approach taken, being using arrays or an intermediary collection to store the relation data in as an alternative to "growing arrays" within the documents, then the obvious thing you should be noting is that the .populate() calls used are actually making additional queries to MongoDB and pulling those documents over the network in separate requests.

                  這在小劑量下可能看起來一切都很好,但是隨著事情的擴(kuò)大,尤其是請求數(shù)量的增加,這絕不是一件好事.此外,您可能還想應(yīng)用其他條件,這意味著您不需要從服務(wù)器中提取所有文檔,而是在返回結(jié)果之前匹配這些關(guān)系"中的數(shù)據(jù).

                  This might appear all well and fine in small doses, however as things scale up and especially over volumes of requests, this is never a good thing. Additionally there might well be other conditions you want to apply that means you don't need to pull all the documents from the server, and would rather match data from those "relations" before you returned results.

                  這就是為什么現(xiàn)代 MongoDB 版本包含 $lookup 實(shí)際上加入"服務(wù)器本身的數(shù)據(jù).到目前為止,您應(yīng)該已經(jīng)查看了這些 API 調(diào)用產(chǎn)生的所有輸出,如 mongoose.set('debug',true) 所示.

                  This is why modern MongoDB releases include $lookup which actually "joins" the data on the server itself. By now you should have been looking at all the output those API calls produce as shown by mongoose.set('debug',true).

                  所以這次我們不是產(chǎn)生多個查詢,而是將其作為一條聚合語句在服務(wù)器上加入",并在一個請求中返回結(jié)果:

                  So instead of producing multiple queries, this time we make it one aggregation statement to "join" on the server, and return the results in one request:

                  // Show Stores
                  let stores = await Store.aggregate([
                    { '$lookup': {
                      'from': StoreItem.collection.name,
                      'let': { 'id': '$_id' },
                      'pipeline': [
                        { '$match': {
                          '$expr': { '$eq': [ '$$id', '$storeId' ] }
                        }},
                        { '$lookup': {
                          'from': Item.collection.name,
                          'let': { 'itemId': '$itemId' },
                          'pipeline': [
                            { '$match': {
                              '$expr': { '$eq': [ '$_id', '$$itemId' ] }
                            }}
                          ],
                          'as': 'items'
                        }},
                        { '$unwind': '$items' },
                        { '$replaceRoot': { 'newRoot': '$items' } }
                      ],
                      'as': 'items'
                    }}
                  ])
                  log(stores);
                  

                  雖然編碼時間更長,但即使對于這里非常微不足道的操作,實(shí)際上效率也高得多.這當(dāng)然是相當(dāng)可觀的.

                  Which whilst longer in coding, is actually far superior in efficiency even for the very trivial action right here. This of course scales considerably.

                  遵循與以前相同的中介"模型(例如,因為它可以通過任何一種方式完成),我們有一個完整的列表:

                  Following the same "intermediary" model as before ( and just for example, because it could be done either way ) we have a full listing:

                  const { Schema } = mongoose = require('mongoose');
                  
                  const uri = 'mongodb://localhost:27017/manydemo',
                        options = { useNewUrlParser: true };
                  
                  mongoose.Promise = global.Promise;
                  mongoose.set('debug', true);
                  mongoose.set('useFindAndModify', false);
                  mongoose.set('useCreateIndex', true);
                  
                  const itemSchema = new Schema({
                    name: String
                  }, {
                    toJSON: { virtuals: true }
                  });
                  
                  itemSchema.virtual('stores', {
                    ref: 'StoreItem',
                    localField: '_id',
                    foreignField: 'itemId'
                  });
                  
                  const storeSchema = new Schema({
                    name: String
                  }, {
                    toJSON: { virtuals: true }
                  });
                  
                  storeSchema.virtual('items', {
                    ref: 'StoreItem',
                    localField: '_id',
                    foreignField: 'storeId'
                  });
                  
                  const storeItemSchema = new Schema({
                    storeId: { type: Schema.Types.ObjectId, ref: 'Store', required: true },
                    itemId: { type: Schema.Types.ObjectId, ref: 'Item', required: true }
                  });
                  
                  const Item = mongoose.model('Item', itemSchema);
                  const Store = mongoose.model('Store', storeSchema);
                  const StoreItem = mongoose.model('StoreItem', storeItemSchema);
                  
                  const log = data => console.log(JSON.stringify(data, undefined, 2));
                  
                  (async function() {
                  
                    try {
                  
                      const conn = await mongoose.connect(uri, options);
                  
                      // Clean data
                      await Promise.all(
                        Object.entries(conn.models).map(([k,m]) => m.deleteMany())
                      );
                  
                      // Create some instances
                      let [toothpaste, brush] = await Item.insertMany(
                        ['toothpaste', 'brush'].map(name => ({ name }) )
                      );
                      let [billsStore, tedsStore] = await Store.insertMany(
                        ['Bills', 'Teds'].map( name => ({ name }) )
                      );
                  
                      // Add toothpaste to both stores
                      for ( let { _id: storeId }  of [billsStore, tedsStore] ) {
                        await StoreItem.updateOne(
                          { storeId, itemId: toothpaste._id },
                          { },
                          { 'upsert': true }
                        );
                      }
                  
                      // Add brush to billsStore
                      await StoreItem.updateOne(
                        { storeId: billsStore._id, itemId: brush._id },
                        { },
                        { 'upsert': true }
                      );
                  
                      // Show Stores
                      let stores = await Store.aggregate([
                        { '$lookup': {
                          'from': StoreItem.collection.name,
                          'let': { 'id': '$_id' },
                          'pipeline': [
                            { '$match': {
                              '$expr': { '$eq': [ '$$id', '$storeId' ] }
                            }},
                            { '$lookup': {
                              'from': Item.collection.name,
                              'let': { 'itemId': '$itemId' },
                              'pipeline': [
                                { '$match': {
                                  '$expr': { '$eq': [ '$_id', '$$itemId' ] }
                                }}
                              ],
                              'as': 'items'
                            }},
                            { '$unwind': '$items' },
                            { '$replaceRoot': { 'newRoot': '$items' } }
                          ],
                          'as': 'items'
                        }}
                      ])
                  
                      log(stores);
                  
                      // Show Items
                      let items = await Item.aggregate([
                        { '$lookup': {
                          'from': StoreItem.collection.name,
                          'let': { 'id': '$_id' },
                          'pipeline': [
                            { '$match': {
                              '$expr': { '$eq': [ '$$id', '$itemId' ] }
                            }},
                            { '$lookup': {
                              'from': Store.collection.name,
                              'let': { 'storeId': '$storeId' },
                              'pipeline': [
                                { '$match': {
                                  '$expr': { '$eq': [ '$_id', '$$storeId' ] }
                                }}
                              ],
                              'as': 'stores',
                            }},
                            { '$unwind': '$stores' },
                            { '$replaceRoot': { 'newRoot': '$stores' } }
                          ],
                          'as': 'stores'
                        }}
                      ]);
                  
                      log(items);
                  
                  
                    } catch(e) {
                      console.error(e);
                    } finally {
                      mongoose.disconnect();
                    }
                  
                  })()
                  

                  還有輸出:

                  Mongoose: stores.aggregate([ { '$lookup': { from: 'storeitems', let: { id: '$_id' }, pipeline: [ { '$match': { '$expr': { '$eq': [ '$$id', '$storeId' ] } } }, { '$lookup': { from: 'items', let: { itemId: '$itemId' }, pipeline: [ { '$match': { '$expr': { '$eq': [ '$_id', '$$itemId' ] } } } ], as: 'items' } }, { '$unwind': '$items' }, { '$replaceRoot': { newRoot: '$items' } } ], as: 'items' } } ], {})
                  [
                    {
                      "_id": "5ca7210717dadc69652b37da",
                      "name": "Bills",
                      "__v": 0,
                      "items": [
                        {
                          "_id": "5ca7210717dadc69652b37d8",
                          "name": "toothpaste",
                          "__v": 0
                        },
                        {
                          "_id": "5ca7210717dadc69652b37d9",
                          "name": "brush",
                          "__v": 0
                        }
                      ]
                    },
                    {
                      "_id": "5ca7210717dadc69652b37db",
                      "name": "Teds",
                      "__v": 0,
                      "items": [
                        {
                          "_id": "5ca7210717dadc69652b37d8",
                          "name": "toothpaste",
                          "__v": 0
                        }
                      ]
                    }
                  ]
                  Mongoose: items.aggregate([ { '$lookup': { from: 'storeitems', let: { id: '$_id' }, pipeline: [ { '$match': { '$expr': { '$eq': [ '$$id', '$itemId' ] } } }, { '$lookup': { from: 'stores', let: { storeId: '$storeId' }, pipeline: [ { '$match': { '$expr': { '$eq': [ '$_id', '$$storeId' ] } } } ], as: 'stores' } }, { '$unwind': '$stores' }, { '$replaceRoot': { newRoot: '$stores' } } ], as: 'stores' } } ], {})
                  [
                    {
                      "_id": "5ca7210717dadc69652b37d8",
                      "name": "toothpaste",
                      "__v": 0,
                      "stores": [
                        {
                          "_id": "5ca7210717dadc69652b37da",
                          "name": "Bills",
                          "__v": 0
                        },
                        {
                          "_id": "5ca7210717dadc69652b37db",
                          "name": "Teds",
                          "__v": 0
                        }
                      ]
                    },
                    {
                      "_id": "5ca7210717dadc69652b37d9",
                      "name": "brush",
                      "__v": 0,
                      "stores": [
                        {
                          "_id": "5ca7210717dadc69652b37da",
                          "name": "Bills",
                          "__v": 0
                        }
                      ]
                    }
                  ]
                  

                  顯而易見的是,為了返回已連接"數(shù)據(jù)形式而發(fā)出的查詢顯著減少.這意味著由于消除了所有網(wǎng)絡(luò)開銷,延遲更低,應(yīng)用程序響應(yīng)速度更快.

                  What should be obvious is the significant reduction in the queries issued on the end to return the "joined" form of the data. This means lower latency and more responsive applications as a result of removing all the network overhead.

                  這些通常是您處理多對多"關(guān)系的方法,基本上可以歸結(jié)為:

                  Those a are generally your approaches to dealing with "many to many" relations, which essentially comes down to either:

                  • 在每個文檔的任一側(cè)保留數(shù)組,保存對相關(guān)項目的引用.

                  • Keeping arrays in each document on either side holding the references to the related items.

                  存儲中間集合并將其用作檢索其他數(shù)據(jù)的查找參考.

                  Storing an intermediary collection and using that as a lookup reference to retrieving the other data.

                  在所有情況下,如果您希望事情在雙向"上起作用,則由您實(shí)際存儲這些引用.當(dāng)然 $lookup 甚至"virtuals",這意味著您并不總是需要存儲在每個源上,因為您可以只在一個地方引用"并通過應(yīng)用這些方法來使用該信息.

                  In all cases it is up to you to actually store those references if you expect things to work on "both directions". Of course $lookup and even "virtuals" where that applies means that you don't always need to store on every source since you could then "reference" in just one place and use that information by applying those methods.

                  另一種情況當(dāng)然是嵌入",這是一個完全不同的游戲,以及 MongoDB 等面向文檔的數(shù)據(jù)庫的真正意義所在.因此,這個概念當(dāng)然不是從另一個集合中獲取",而是嵌入"數(shù)據(jù).

                  The other case is of course "embedding", which is an entirely different game and what document oriented databases such as MongoDB are really all about. Therefore instead of "fetching from another collection" the concept is of course to "embed" the data.

                  這不僅意味著指向其他項目的 ObjectId 值,而且實(shí)際上將完整數(shù)據(jù)存儲在每個文檔的數(shù)組中.當(dāng)然存在大小"問題,當(dāng)然還有在多個地方更新數(shù)據(jù)的問題.這通常是一個單個請求和一個簡單請求的權(quán)衡,不需要去其他集合中查找數(shù)據(jù),因為它已經(jīng)存在".

                  This means not just the ObjectId values that point to the other items, but actually storing the full data within arrays in each document. There is of course an issue of "size" and of course issues with updating data in multiple places. This is generally the trade off for there being a single request and a simple request that does not need to go and find data in other collections because it's "already there".

                  關(guān)于引用與嵌入的主題有很多材料.一旦這樣的摘要來源是 Mongoose 填充 vs 對象嵌套,甚至是非常通用的 MongoDB 關(guān)系:嵌入還是引用? 等等.

                  There is plenty of material around on the subject of referencing vs embedding. Once such summary source is Mongoose populate vs object nesting or even the very general MongoDB relationships: embed or reference? and many many others.

                  您應(yīng)該花一些時間來思考這些概念以及如何將其應(yīng)用于您的一般應(yīng)用程序.請注意,您實(shí)際上并沒有在這里使用 RDBMS,因此您最好使用您打算利用的正確功能,而不是簡單地讓一個行為像另一個一樣.

                  You should spend some time thinking about the concepts and how this applies to your application in general. And note that you are not actually using an RDBMS here, so you might as well use the correct features that you are meant to exploit, rather than simply making one act like the other.

                  這篇關(guān)于Mongoose 多對多的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!

                  【網(wǎng)站聲明】本站部分內(nèi)容來源于互聯(lián)網(wǎng),旨在幫助大家更快的解決問題,如果有圖片或者內(nèi)容侵犯了您的權(quán)益,請聯(lián)系我們刪除處理,感謝您的支持!

                  相關(guān)文檔推薦

                  Use IScroll in Angular 2 / Typescript(在 Angular 2/Typescript 中使用 IScroll)
                  anime.js not working in Ionic 3 project(Anime.js 在 Ionic 3 項目中不起作用)
                  Ionic 3 - Update Observable with Asynchronous Data(Ionic 3 - 使用異步數(shù)據(jù)更新 Observable)
                  Angular 2: file not found on local .json file(Angular 2:在本地 .json 文件中找不到文件)
                  In Ionic 2, how do I create a custom directive that uses Ionic components?(在 Ionic 2 中,如何創(chuàng)建使用 Ionic 組件的自定義指令?)
                  Use ViewChild for dynamic elements - Angular 2 amp; ionic 2(將 ViewChild 用于動態(tài)元素 - Angular 2 amp;離子2)

                    <bdo id='7Yl7q'></bdo><ul id='7Yl7q'></ul>

                      <legend id='7Yl7q'><style id='7Yl7q'><dir id='7Yl7q'><q id='7Yl7q'></q></dir></style></legend>
                    1. <i id='7Yl7q'><tr id='7Yl7q'><dt id='7Yl7q'><q id='7Yl7q'><span id='7Yl7q'><b id='7Yl7q'><form id='7Yl7q'><ins id='7Yl7q'></ins><ul id='7Yl7q'></ul><sub id='7Yl7q'></sub></form><legend id='7Yl7q'></legend><bdo id='7Yl7q'><pre id='7Yl7q'><center id='7Yl7q'></center></pre></bdo></b><th id='7Yl7q'></th></span></q></dt></tr></i><div class="by0uqs0" id='7Yl7q'><tfoot id='7Yl7q'></tfoot><dl id='7Yl7q'><fieldset id='7Yl7q'></fieldset></dl></div>
                        <tbody id='7Yl7q'></tbody>
                          <tfoot id='7Yl7q'></tfoot>

                          • <small id='7Yl7q'></small><noframes id='7Yl7q'>

                            主站蜘蛛池模板: 北京公寓出租网-北京酒店式公寓出租平台| 全自动包衣机-无菌分装隔离器-浙江迦南科技股份有限公司 | 智能化的检漏仪_气密性测试仪_流量测试仪_流阻阻力测试仪_呼吸管快速检漏仪_连接器防水测试仪_车载镜头测试仪_奥图自动化科技 | 芜湖厨房设备_芜湖商用厨具_芜湖厨具设备-芜湖鑫环厨具有限公司 控显科技 - 工控一体机、工业显示器、工业平板电脑源头厂家 | 【铜排折弯机,钢丝折弯成型机,汽车发泡钢丝折弯机,线材折弯机厂家,线材成型机,铁线折弯机】贝朗折弯机厂家_东莞市贝朗自动化设备有限公司 | 吹塑加工_大型吹塑加工_滚塑代加工-莱力奇吹塑加工有限公司 | 掺铥光纤放大器-C/L波段光纤放大器-小信号光纤放大器-合肥脉锐光电技术有限公司 | 消泡剂-水处理消泡剂-涂料消泡剂-切削液消泡剂价格-东莞德丰消泡剂厂家 | 国标白水泥,高标号白水泥,白水泥厂家-淄博华雪建材有限公司 | 广东西屋电气有限公司-广东西屋电气有限公司 | 山东太阳能路灯厂家-庭院灯生产厂家-济南晟启灯饰有限公司 | 齿轮减速马达一体式_蜗轮蜗杆减速机配电机-德国BOSERL齿轮减速电动机生产厂家 | 塑料异型材_PVC异型材_封边条生产厂家_PC灯罩_防撞扶手_医院扶手价格_东莞市怡美塑胶制品有限公司 | 硬质合金模具_硬质合金非标定制_硬面加工「生产厂家」-西迪技术股份有限公司 | 电动葫芦-河北悍象起重机械有限公司| 考勤系统_人事考勤管理系统_本地部署BS考勤系统_考勤软件_天时考勤管理专家 | 圆形振动筛_圆筛_旋振筛_三次元振动筛-河南新乡德诚生产厂家 | 新车测评网_网罗汽车评测资讯_汽车评测门户报道 | 威海防火彩钢板,威海岩棉复合板,威海彩钢瓦-文登区九龙岩棉复合板厂 | 车间除尘设备,VOCs废气处理,工业涂装流水线,伸缩式喷漆房,自动喷砂房,沸石转轮浓缩吸附,机器人喷粉线-山东创杰智慧 | ★塑料拖链__工程拖链__电缆拖链__钢制拖链 - 【上海闵彬】 | 槽钢冲孔机,槽钢三面冲,带钢冲孔机-山东兴田阳光智能装备股份有限公司 | 品牌广告服务平台,好排名,好流量,好生意。 | 高效节能电机_伺服主轴电机_铜转子电机_交流感应伺服电机_图片_型号_江苏智马科技有限公司 | 昆明化妆培训-纹绣美甲-美容美牙培训-昆明博澜培训学校 | 上海办公室设计_办公楼,写字楼装修_办公室装修公司-匠御设计 | 德州万泰装饰 - 万泰装饰装修设计软装家居馆 | 哈尔滨发电机,黑龙江柴油发电机组-北方星光 | 合肥花魁情感婚姻咨询中心_挽回爱情_修复婚姻_恋爱指南 | 电动葫芦|防爆钢丝绳电动葫芦|手拉葫芦-保定大力起重葫芦有限公司 | 银川美容培训-美睫美甲培训-彩妆纹绣培训-新娘化妆-学化妆-宁夏倍莱妮职业技能培训学校有限公司 临时厕所租赁_玻璃钢厕所租赁_蹲式|坐式厕所出租-北京慧海通 | 黄石东方妇产医院_黄石妇科医院哪家好_黄石无痛人流医院 | 代做标书-代写标书-专业标书文件编辑-「深圳卓越创兴公司」 | app开发|app开发公司|小程序开发|物联网开发||北京网站制作|--前潮网络 | 北京模型公司-军事模型-工业模型制作-北京百艺模型沙盘公司 | 卫生型双针压力表-高温防腐差压表-安徽康泰电气有限公司 | 振动筛,震动筛,圆形振动筛,振动筛价格,振动筛厂家-新乡巨宝机电 蒸汽热收缩机_蒸汽发生器_塑封机_包膜机_封切收缩机_热收缩包装机_真空机_全自动打包机_捆扎机_封箱机-东莞市中堡智能科技有限公司 | 蓝莓施肥机,智能施肥机,自动施肥机,水肥一体化项目,水肥一体机厂家,小型施肥机,圣大节水,滴灌施工方案,山东圣大节水科技有限公司官网17864474793 | 北京四合院出租,北京四合院出售,北京平房买卖 - 顺益兴四合院 | 不锈钢列管式冷凝器,换热器厂家-无锡飞尔诺环境工程有限公司 | 合肥通道闸-安徽车牌识别-人脸识别系统厂家-安徽熵控智能技术有限公司 |