2017-07-06 4 views
-1

So habe ich zwei Schemas, Artikel und Ereignis Beide haben ein Bildfeld.So verwenden Sie verschiedene Arten von Referenzen und füllen

Für Artikel,

featured_image: { 
    type: String, 
    default: '', 
} 

Für Ereignis,

featured_image: { 
    type: Schema.ObjectId, 
    ref: 'Medium' 
} 

ich ein anderes Schema haben, Card, wie dieser

type: { 
    type: String, 
    enum: ['Article', 'Event'] 
}, 
data: { 
    type: Schema.ObjectId, 
    refPath: 'type'  
} 

Ich versuche, um die Karten zu bevölkern, wie dies

Card 
    .find(query) 
    .populate({ 
      path: 'data', 
      populate: [{ 
       path: 'featured_image', 
       model: 'Medium', 
       select: 'source type' 
      }] 
    };) 

Allerdings gibt es mir weiterhin einen Cast-Fehler, denn wenn die Karte vom Typ Event ist, füllt sie gut aus, aber wenn sie vom Typ 'Article' ist, hat das featured_image-Feld einen String-Typ und kann daher nicht ausgefüllt werden.

Wie befülle ich featured_image Feld nur, wenn die Karte vom Typ Event oder es ist eine Referenz-ID, anstelle von String.

+0

Gibt es etwas in der mitgelieferten Antwort, die Sie glaubt nicht, Ihre Frage zu beantworten? Wenn ja, dann kommentieren Sie bitte die Antwort, um zu klären, was genau adressiert werden muss, was nicht der Fall ist. Wenn es tatsächlich die Frage beantwortet, die Sie gestellt haben, dann beachten Sie bitte [Akzeptieren Sie Ihre Antworten] (https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) zu den Fragen, die Sie haben fragen Sie –

+0

"Bump". Noch keine Antwort? –

Antwort

0

Statt dessen, was Sie versuchen zu tun, sollten Sie "Diskriminatoren" verwenden, was in der Tat der richtige Weg ist, eine Beziehung zu handhaben, bei der die Objekttypen in der angegebenen Referenz variieren.

Sie verwenden Scheidern durch die unterschiedliche Art und Weise, in der Sie das Modell definieren, die anstelle von einem „Basismodell“ konstruiert und Schema wie in:

const contentSchema = new Schema({ 
    name: String 
}); 

const articleSchema = new Schema({ 
    image: String, 
}); 

const eventSchema = new Schema({ 
    image: { type: Schema.Types.ObjectId, ref: 'Medium' } 
}); 

const cardSchema = new Schema({ 
    name: String, 
    data: { type: Schema.Types.ObjectId, ref: 'Content' } 
}); 

const Medium = mongoose.model('Medium', mediumSchema); 
const Card = mongoose.model('Card', cardSchema) 

const Content = mongoose.model('Content', contentSchema); 
const Article = Content.discriminator('Article', articleSchema); 
const Event = Content.discriminator('Event', eventSchema); 

Anstatt also Sie ein „Basismodell“ definieren, wie Content hier, worauf Sie die Referenzen tatsächlich zeigen innerhalb Event. Der nächste Teil besteht darin, dass das abweichende Schema für dieses Modell tatsächlich über die .discriminator()-Methode aus dem Basismodell registriert wird, im Gegensatz zur .model()-Methode. Dadurch wird das Schema mit dem allgemeinen Modell Content so registriert, dass beim Angeben einer mit .discriminator() definierten Modellinstanz unter Verwendung des registrierten Modellnamens ein spezielles Feld __t in diesen Daten enthalten ist.

Abgesehen von Mungo zu .populate() auf verschiedenen Typen zu aktivieren, hat dies auch den Vorteil, ein "vollständiges Schema" zu den verschiedenen Arten von Elementen. Sie haben also verschiedene Validierungsmethoden und andere Methoden, wenn Sie möchten. Es ist in der Tat "Polymorphismus" bei der Arbeit in einem Datenbankkontext, mit hilfreichen Schema-Objekten beigefügt.

Daher können wir sowohl die verschiedenen "Joins" demonstrieren, die ausgeführt werden, als auch, dass Sie jetzt die einzelnen Modelle für Article und Event verwenden können, die nur die Elemente in allen Abfragen und Operationen behandeln würden. Und nicht nur können Sie "einzeln" verwenden, aber da der Mechanismus dafür die Daten in der gleichen Sammlung speichert, gibt es auch ein Content Modell, das Zugang zu diesen beiden Typen gibt. Das ist im Wesentlichen, wie die Hauptbeziehung in der Definition zum Event Schema funktioniert.

Als vollständige Liste

const async = require('async'), 
     mongoose = require('mongoose'), 
     Schema = mongoose.Schema; 

mongoose.set('debug',true); 
mongoose.Promise = global.Promise; 

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

const mediumSchema = new Schema({ 
    title: String 
}); 

const contentSchema = new Schema({ 
    name: String 
}); 

const articleSchema = new Schema({ 
    image: String, 
}); 

const eventSchema = new Schema({ 
    image: { type: Schema.Types.ObjectId, ref: 'Medium' } 
}); 

const cardSchema = new Schema({ 
    name: String, 
    data: { type: Schema.Types.ObjectId, ref: 'Content' } 
}); 

const Medium = mongoose.model('Medium', mediumSchema); 
const Card = mongoose.model('Card', cardSchema) 

const Content = mongoose.model('Content', contentSchema); 
const Article = Content.discriminator('Article', articleSchema); 
const Event = Content.discriminator('Event', eventSchema); 

function log(data) { 
    console.log(JSON.stringify(data, undefined, 2)) 
} 

async.series(
    [ 
    // Clean data 
    (callback) => 
     async.each(mongoose.models,(model,callback) => 
     model.remove({},callback),callback), 

    // Insert some data 
    (callback) => 
     async.waterfall(
     [ 
      (callback) => 
      Medium.create({ title: 'An Image' },callback), 

      (medium,callback) => 
      Content.create(
       [ 
       { name: "An Event", image: medium, __t: 'Event' }, 
       { name: "An Article", image: "A String", __t: 'Article' } 
       ], 
       callback 
      ), 

      (content,callback) => 
      Card.create(
       [ 
       { name: 'Card 1', data: content[0] }, 
       { name: 'Card 2', data: content[1] } 
       ], 
       callback 
      ) 
     ], 
     callback 
    ), 

    // Query and populate 
    (callback) => 
     Card.find() 
     .populate({ 
      path: 'data', 
      populate: [{ 
      path: 'image' 
      }] 
     }) 
     .exec((err,cards) => { 
     if (err) callback(err); 
     log(cards); 
     callback(); 
     }), 

    // Query on the model for the discriminator 
    (callback) => 
     Article.findOne({},(err,article) => { 
     if (err) callback(err); 
     log(article); 
     callback(); 
     }), 

    // Query on the general Content model 
    (callback) => 
     Content.find({},(err,contents) => { 
     if (err) callback(err); 
     log(contents); 
     callback(); 
     }), 


    ], 
    (err) => { 
    if (err) throw err; 
    mongoose.disconnect(); 
    } 
); 

Und der Beispielausgabe für verschiedene Abfragen

Mongoose: cards.find({}, { fields: {} }) 
Mongoose: contents.find({ _id: { '$in': [ ObjectId("595ef117175f6850dcf657d7"), ObjectId("595ef117175f6850dcf657d6") ] } }, { fields: {} }) 
Mongoose: media.find({ _id: { '$in': [ ObjectId("595ef117175f6850dcf657d5") ] } }, { fields: {} }) 
[ 
    { 
    "_id": "595ef117175f6850dcf657d9", 
    "name": "Card 2", 
    "data": { 
     "_id": "595ef117175f6850dcf657d7", 
     "name": "An Article", 
     "image": "A String", 
     "__v": 0, 
     "__t": "Article" 
    }, 
    "__v": 0 
    }, 
    { 
    "_id": "595ef117175f6850dcf657d8", 
    "name": "Card 1", 
    "data": { 
     "_id": "595ef117175f6850dcf657d6", 
     "name": "An Event", 
     "image": { 
     "_id": "595ef117175f6850dcf657d5", 
     "title": "An Image", 
     "__v": 0 
     }, 
     "__v": 0, 
     "__t": "Event" 
    }, 
    "__v": 0 
    } 
] 
Mongoose: contents.findOne({ __t: 'Article' }, { fields: {} }) 
{ 
    "_id": "595ef117175f6850dcf657d7", 
    "name": "An Article", 
    "image": "A String", 
    "__v": 0, 
    "__t": "Article" 
} 
Mongoose: contents.find({}, { fields: {} }) 
[ 
    { 
    "_id": "595ef117175f6850dcf657d6", 
    "name": "An Event", 
    "image": "595ef117175f6850dcf657d5", 
    "__v": 0, 
    "__t": "Event" 
    }, 
    { 
    "_id": "595ef117175f6850dcf657d7", 
    "name": "An Article", 
    "image": "A String", 
    "__v": 0, 
    "__t": "Article" 
    } 
] 
Verwandte Themen