sql >> Database teknologi >  >> NoSQL >> MongoDB

Flere skemareferencer i enkelt skemaarray - mongoose

Det du leder efter her er mangusten .discriminator() metode. Dette giver dig dybest set mulighed for at gemme objekter af forskellige typer i samme samling, men have dem som særskilte førsteklasses objekter.

Bemærk, at "samme samling"-princippet her er vigtigt for hvordan .populate() værker og definitionen af ​​referencen i den indeholdende model. Da du i virkeligheden kun kan pege på "én" model som reference alligevel, men der er noget andet magi, der kan få en model til at fremstå lige så mange.

Eksempel på liste:

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

Og output

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

Du kan også fjerne kommentarer til mongoose.set("debug",true) linje i listen for at se, hvordan mongoose faktisk konstruerer opkaldene.

Så hvad dette viser er, at du kan anvende forskellige skemaer til forskellige førsteklasses objekter, og endda med forskellige metoder knyttet til dem ligesom rigtige objekter. Mongoose gemmer alle disse i en "våben"-samling med den vedhæftede model, og den vil indeholde alle "typer", der henvises til af diskriminatoren:

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

Men også hver anden "type" er refereret med sin egen model på en særlig måde. Så du kan se, at når mongoose gemmer og læser objektet, er der en særlig __t felt, som fortæller hvilken "model" den skal anvende, og dermed vedhæftet skema.

Som et eksempel kalder vi .shoot() metode, som er defineret forskelligt for hver model/skema. Og du kan også stadig bruge hver enkelt model for sig selv til forespørgsler eller andre operationer, da Ak47 vil automatisk anvende __t værdi i alle forespørgsler/opdateringer.

Så selvom lageret er i én samling, kan det se ud til at være mange samlinger, men har også fordelen af ​​at holde dem sammen til andre nyttige operationer. Sådan kan du anvende den slags "polymorfi", du leder efter.




  1. Mongoose-opdatering uden tilbagekald

  2. Tips til fjernstyring af MongoDB

  3. Hent positionen for det valgte dokument i samlingen [mongoDB]

  4. Cassandra vs. MongoDB:hvilken skal du vælge