sql >> Databasteknik >  >> NoSQL >> MongoDB

Flera schemareferenser i en enda schemamatris - mongoose

Det du letar efter här är mungosen .discriminator() metod. Detta låter dig i princip lagra objekt av olika typer i samma samling, men ha dem som urskiljbara förstklassiga objekt.

Observera att principen "samma samling" här är viktig för hur .populate() verk och definitionen av referensen i den innehållande modellen. Eftersom du egentligen bara kan peka på "en" modell för en referens ändå, men det finns någon annan magi som kan få en modell att synas lika många.

Exempellista:

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

Och utdata

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 också avkommentera mongoose.set("debug",true) rad i listan för att se hur mongoose faktiskt konstruerar samtalen.

Så vad detta visar är att du kan tillämpa olika scheman på olika förstklassiga objekt, och även med olika metoder kopplade till dem precis som riktiga objekt. Mongoose lagrar alla dessa i en "vapen"-samling med den bifogade modellen, och den kommer att innehålla alla "typer" som hänvisas till av diskriminatorn:

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

Men också varje "typ" refereras med sin egen modell på ett speciellt sätt. Så du ser att när mongoose lagrar och läser objektet finns det en speciell __t fält som talar om vilken "modell" som ska tillämpas, och därmed bifogat schema.

Som ett exempel kallar vi .shoot() metod, som definieras olika för varje modell/schema. Och du kan fortfarande använda var och en som en modell för sig själv för frågor eller andra operationer, eftersom Ak47 kommer automatiskt att tillämpa __t värde i alla frågor/uppdateringar.

Så även om lagringen finns i en samling kan det verka som många samlingar, men har också fördelen av att hålla dem samman för andra användbara operationer. Så här kan du tillämpa den typ av "polymorfism" du letar efter.




  1. Node.js Redis Connection Pooling

  2. Vad är användningen av Jade eller Handlebars när du skriver AngularJs appar

  3. Hur man separerar redis-databas för samma två app i node.js

  4. MongoDB / Pymongo-fråga med Datetime