sql >> Database >  >> NoSQL >> MongoDB

Meerdere schemaverwijzingen in een enkele schemaarray - mangoest

Wat je hier zoekt is de mangoest .discriminator() methode. Dit stelt u in feite in staat om objecten van verschillende typen in dezelfde collectie op te slaan, maar ze als te onderscheiden eersteklas objecten te hebben.

Merk op dat het "dezelfde verzameling"-principe hier belangrijk is voor hoe .populate() werken en de definitie van de referentie in het bevattende model. Omdat je eigenlijk maar "één" model als referentie kunt aanwijzen, maar er is een andere magie die ervoor kan zorgen dat één model evenveel lijkt.

Voorbeeldlijst:

var util = require('util'),
    async = require('async'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/gunshow');

//mongoose.set("debug",true);

var scenarioSchema = new Schema({
  "name": String,
  "guns": [{ "type": Schema.Types.ObjectId, "ref": "Gun" }]
});

function BaseSchema() {
  Schema.apply(this, arguments);

  // Common Gun stuff
  this.add({
    "createdAt": { "type": Date, "default": Date.now }
  });
}

util.inherits(BaseSchema, Schema);

var gunSchema = new BaseSchema();

var ak47Schema = new BaseSchema({
  // Ak74 stuff
});

ak47Schema.methods.shoot = function() {
  return "Crack!Crack";
};

var m16Schema = new BaseSchema({
  // M16 Stuff
});

m16Schema.methods.shoot = function() {
  return "Blam!!"
};


var Scenario = mongoose.model("Scenario", scenarioSchema);

var Gun = mongoose.model("Gun", gunSchema );
var Ak47 = Gun.discriminator("Ak47", ak47Schema );
var M16 = Gun.discriminator("M16", m16Schema );


async.series(
  [
    // Cleanup
    function(callback) {
      async.each([Scenario,Gun],function(model,callback) {
        model.remove({},callback);
      },callback);
    },

    // Add some guns and add to scenario
    function(callback) {
      async.waterfall(
        [
          function(callback) {
            async.map([Ak47,M16],function(gun,callback) {
              gun.create({},callback);
            },callback);
          },
          function(guns,callback) {
            Scenario.create({
              "name": "Test",
              "guns": guns
            },callback);
          }
        ],
        callback
      );
    },

    // Get populated scenario
    function(callback) {
      Scenario.findOne().populate("guns").exec(function(err,data) {

        console.log("Populated:\n%s",JSON.stringify(data,undefined,2));

        // Shoot each gun for fun!
        data.guns.forEach(function(gun) {
          console.log("%s says %s",gun.__t,gun.shoot());
        });

        callback(err);
      });
    },

    // Show the Guns collection
    function(callback) {
      Gun.find().exec(function(err,guns) {
        console.log("Guns:\n%s", JSON.stringify(guns,undefined,2));
        callback(err);
      });
    },

    // Show magic filtering
    function(callback) {
      Ak47.find().exec(function(err,ak47) {
        console.log("Magic!:\n%s", JSON.stringify(ak47,undefined,2));
        callback(err);
      });
    }
  ],
  function(err) {
    if (err) throw err;
    mongoose.disconnect();
  }
);

En uitvoer

Populated:
{
  "_id": "56c508069d16fab84ead921d",
  "name": "Test",
  "__v": 0,
  "guns": [
    {
      "_id": "56c508069d16fab84ead921b",
      "__v": 0,
      "__t": "Ak47",
      "createdAt": "2016-02-17T23:53:42.853Z"
    },
    {
      "_id": "56c508069d16fab84ead921c",
      "__v": 0,
      "__t": "M16",
      "createdAt": "2016-02-17T23:53:42.862Z"
    }
  ]
}
Ak47 says Crack!Crack
M16 says Blam!!
Guns:
[
  {
    "_id": "56c508069d16fab84ead921b",
    "__v": 0,
    "__t": "Ak47",
    "createdAt": "2016-02-17T23:53:42.853Z"
  },
  {
    "_id": "56c508069d16fab84ead921c",
    "__v": 0,
    "__t": "M16",
    "createdAt": "2016-02-17T23:53:42.862Z"
  }
]
Magic!:
[
  {
    "_id": "56c508069d16fab84ead921b",
    "__v": 0,
    "__t": "Ak47",
    "createdAt": "2016-02-17T23:53:42.853Z"
  }
]

U kunt ook het commentaar van de mongoose.set("debug",true) . verwijderen regel in de lijst om te zien hoe mangoest de oproepen daadwerkelijk opbouwt.

Dit laat zien dat je verschillende schema's kunt toepassen op verschillende eersteklas objecten, en zelfs met verschillende methoden eraan gekoppeld, net als echte objecten. Mongoose slaat deze allemaal op in een "wapens"-verzameling met het bijgevoegde model, en het zal alle "types" bevatten waarnaar door de discriminator wordt verwezen:

var Gun = mongoose.model("Gun", gunSchema );
var Ak47 = Gun.discriminator("Ak47", ak47Schema );
var M16 = Gun.discriminator("M16", m16Schema );

Maar ook naar elk ander "type" wordt op een speciale manier verwezen met zijn eigen model. Dus je ziet dat wanneer mangoest het object opslaat en leest, er een speciale __t . is veld dat aangeeft welk "model" moet worden toegepast, en dus het bijgevoegde schema.

Als een voorbeeld noemen we de .shoot() methode, die voor elk model/schema anders is gedefinieerd. En u kunt elk ook nog steeds als een afzonderlijk model gebruiken voor query's of andere bewerkingen, aangezien Ak47 zal automatisch de __t . toepassen waarde in alle zoekopdrachten/upates.

Dus hoewel de opslag zich in één verzameling bevindt, kan het lijken alsof het meerdere verzamelingen zijn, maar het heeft ook het voordeel dat ze bij elkaar worden gehouden voor andere nuttige handelingen. Dit is hoe u het soort "polymorfisme" kunt toepassen waarnaar u op zoek bent.




  1. Wat is het verschil tussen id en _id in mangoest?

  2. Gebruik meer dan één schema per verzameling op mongodb

  3. Een MongoDB-verzameling exporteren naar een JSON-bestand

  4. Invloed op de prestatie van de meltdown op MongoDB:AWS, Azure en DigitalOcean