sql >> Databáze >  >> NoSQL >> MongoDB

Vícenásobné odkazy na schéma v jednom poli schémat - mongoose

To, co zde hledáte, je mongoose .discriminator() metoda. To vám v podstatě umožňuje ukládat objekty různých typů do stejné kolekce, ale mít je jako rozlišitelné prvotřídní objekty.

Všimněte si, že princip "stejné kolekce" je důležitý pro to, jak .populate() práce a definice reference v obsahujícím modelu. Vzhledem k tomu, že skutečně můžete ukázat pouze na "jeden" model pro referenci, ale existuje nějaká další magie, díky které se jeden model zobrazí jako více.

Příklad výpisu:

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

A výstup

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

Můžete také odkomentovat mongoose.set("debug",true) řádek ve výpisu, abyste viděli, jak mongoose ve skutečnosti vytváří volání.

Takže to ukazuje, že můžete použít různá schémata na různé objekty první třídy a dokonce s různými metodami, které jsou k nim připojeny, stejně jako na skutečné objekty. Mongoose je všechny ukládá ve sbírce „zbraní“ s připojeným modelem a bude obsahovat všechny „typy“, na které odkazuje diskriminátor:

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

Ale také každý jiný "typ" je odkazován se svým vlastním modelem zvláštním způsobem. Takže vidíte, že když mangusta ukládá a čte objekt, existuje speciální __t pole, které mu říká, který "model" použít, a tedy připojené schéma.

Jako jeden příklad nazýváme .shoot() metoda, která je pro každý model/schéma definována jinak. A také můžete stále používat každý jako samostatný model pro dotazy nebo jiné operace, protože Ak47 automaticky použije __t hodnotu ve všech dotazech/upatech.

Takže i když je úložiště v jedné kolekci, může se zdát, že je to mnoho kolekcí, ale má také tu výhodu, že je drží pohromadě pro další užitečné operace. Takto můžete aplikovat druh „polymorfismu“, který hledáte.




  1. Jak vyhledám objekt podle jeho ObjectId v mongo konzoli?

  2. Jak nasadit MongoDB pro vysokou dostupnost

  3. Jak získat posledních N záznamů v mongodb?

  4. Jak databáze NoSQL fungují na agregovaných funkcích (AVG, SUM atd.)