久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

<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="qwawimqqmiuu" 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="qwawimqqmiuu" 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 多對多的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!

                  問題描述

                  我有兩個模型:

                  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 數組一起保存.item 但是沒有stores.我錯過了什么?如何自動更新 MongoDB/Mongoose 中的多對多關系?我習慣了 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中沒有自動參照完整性",關系"這樣的概念實際上是手動"的事情,實際上 .populate() 的情況實際上是一堆額外的查詢以檢索引用的信息.這里沒有魔法".

                  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.

                  正確處理多對多"歸結為三個選項:

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

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

                  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();
                    }
                  
                  })();
                  

                  這將創建項目"集合:

                  {
                      "_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
                  }
                  

                  并產生整體輸出,例如:

                  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
                        }
                      ]
                    }
                  ]
                  

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

                  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" 數組中,而且還添加了每個 "store"toothpaste 項的 "stores" 數組.這樣做是為了可以從任一方向查詢關系.如果您只想要來自商店的商品"并且從不來自商品的商店",那么您根本不需要將關系數據存儲在商品"條目上.

                  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.

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

                  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();
                    }
                  
                  })();
                  

                  關系現在在它們自己的集合中,所以數據現在顯示不同,對于項目":

                  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"
                  }
                  

                  現在是映射關系的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"
                    }
                  ]
                  

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

                  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() 調用知道要使用什么.

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

                  中間集合有一個相當標準的定義:

                  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 }
                  });
                  

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

                  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 }
                    );
                  }
                  

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

                  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.

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

                  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 - 在服務器上使用 Modern Features 來實現

                  因此,根據所采用的方法,使用數組或中間集合來存儲關系數據作為文檔中不斷增長的數組"的替代方法,那么您應該注意的顯而易見的事情是 .使用的 populate() 調用實際上是對 MongoDB 進行額外的查詢,并在單獨的請求中通過網絡拉取這些文檔.

                  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.

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

                  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.

                  這就是為什么現代 MongoDB 版本包含 $lookup 實際上加入"服務器本身的數據.到目前為止,您應該已經查看了這些 API 調用產生的所有輸出,如 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).

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

                  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);
                  

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

                  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
                        }
                      ]
                    }
                  ]
                  

                  顯而易見的是,為了返回已連接"數據形式而發出的查詢顯著減少.這意味著由于消除了所有網絡開銷,延遲更低,應用程序響應速度更快.

                  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.

                  這些通常是您處理多對多"關系的方法,基本上可以歸結為:

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

                  • 在每個文檔的任一側保留數組,保存對相關項目的引用.

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

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

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

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

                  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.

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

                  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 值,而且實際上將完整數據存儲在每個文檔的數組中.當然存在大小"問題,當然還有在多個地方更新數據的問題.這通常是一個單個請求和一個簡單請求的權衡,不需要去其他集合中查找數據,因為它已經存在".

                  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".

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

                  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.

                  您應該花一些時間來思考這些概念以及如何將其應用于您的一般應用程序.請注意,您實際上并沒有在這里使用 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.

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

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

                  相關文檔推薦

                  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 - 使用異步數據更新 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 中,如何創建使用 Ionic 組件的自定義指令?)
                  Use ViewChild for dynamic elements - Angular 2 amp; ionic 2(將 ViewChild 用于動態元素 - 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="qwawimqqmiuu" 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'>

                            主站蜘蛛池模板: 五月天综合影院 | 国产亚洲欧美另类一区二区三区 | 午夜成人在线视频 | 久久成人免费观看 | 亚洲激情一级片 | 国产精品五区 | 亚洲aⅴ一区二区 | 久久久成人一区二区免费影院 | 91在线 | 综合久久av | 欧美精品中文 | 欧美日韩国产综合在线 | 毛色毛片免费看 | 人人操日日干 | 99久久久久久99国产精品免 | 夜夜摸天天操 | v片网站 | 91天堂网| 日韩视频91 | 亚洲高清一区二区三区 | 在线观看av不卡 | 中文字幕av色 | 久久9999久久 | 一区二区三区观看视频 | 日本成人在线免费视频 | 久久av.com | 成人一区二区三区在线观看 | 91视频在线看 | 亚洲91精品 | 一区二区三区国产 | 在线观看免费观看在线91 | 日韩中文字幕视频在线 | 日本在线免费看最新的电影 | 久久免费视频观看 | av在线三级 | 色五月激情五月 | 午夜影院在线观看 | 久久久久久久久91 | 99在线精品视频 | 日韩一区二区福利 | 欧美日韩亚洲在线 |