Match two models in mongodb

1

I am in trouble to be able to relate two models in mongodb. I was looking for some forums the methods populate() , aggregate() . But they do not work for that matter (I think).

I have model A {title : 'hola'} , model B {id_a : '2der45g', data : 'etc'} . In this case what I want to do is the following:

var reportStatus = function(request, reply) {
        var result = [];
        models.Eventos.find({},{title: 1}, function(err, eventos) {
            if(err) throw err;
            models.Report.find({}).where('evento').equals(eventos[0]._id).exec(function(err, reporte) {
                eventos[0]['reporte'] = reporte;
                reply(JSON.stringify(eventos));
            });
        });
    }

The problem is that when doing print , you are not adding report to the first object A , I understand?

I hope for your help, thank you

    
asked by Necrocyber 10.08.2017 в 16:12
source

2 answers

1

friend I had the same problem but I found a way to relate a document to two others by reference to the ObjectId. I leave the code to see if it works. This with mongoose and echo in Nodejs

In some lines of code was not used "function (err, element) {}", the new form of ECMAScript 6 "(err, element) = > {}".

The models to use.

First model of a "student".

//sirve para poder usar nuevas instrucciones en javascript
'use strict'

//guardamos en una variable las propiedades del modulo mongosse en node_modules
var mongoose = require('mongoose');

//se carga en una variable la propiedad de esquema
//var Schema = mongoose.Schema;

//creamos el esquema en un objeto(se podria decir que es la estructura de una tabla o la de la collecion de mongo)
var AlumnoSchema = mongoose.Schema({
	rut: String,
	nombre: String,
	apaterno: String,
	amaterno: String,
	nacimiento: String,
	edad: Number,
	estadocivil: String,
	nacionalidad: String,
	direccion: String,
	comuna: String,
	celular:String,
	telefono: String,
	correo: String,
	actividad: String,
	escolaridad: String
});

//exportamos el objeto y pasamos 2 parametros
//el primer parametro es el nombre de la coleccion(tabla)
module.exports = mongoose.model('alumno', AlumnoSchema);

Second model of a "course"

//sirve para poder usar nuevas instrucciones en javascript
'use strict'

//guardamos en una variable las propiedades del modulo mongosse en node_modules
var mongoose = require('mongoose');

//se carga en una variable la propiedad de esquema
var Schema = mongoose.Schema;

//creamos el esquema en un objeto(se podria decir que es la estructura de una tabla o la de la collecion de mongo)
var CursosSchema = Schema({
	codigocurso: String,
	lugar: String,
	fechainicio: String,
	fechatermino:String,
});

//exportamos el objeto y pasamos 2 parametros
//el primer parametro es el nombre de la coleccion(tabla)
module.exports = mongoose.model('curso', CursosSchema);

Now the third model where the reference to the ObjectId of the other two previous models is stored. Model of "alumni"

'use strict'

var mongoose = require('mongoose');

var Schema = mongoose.Schema;

var CursoAlumnosSchema = Schema({
	//guardamos el Objetcid del modelo "curso"
	codigocurso: {type: Schema.ObjectId, ref: 'curso' },
	//guardamos el Objetcid del modelo "alumno"
	rutalumno: {type: Schema.ObjectId, ref: 'alumno' },
	licencia: String,
	ncontrato: String,
	total: Number,
	saldo: Number
});

module.exports = mongoose.model('cursoalumno', CursoAlumnosSchema);

Then we created the function to obtain all the elements of the "pupils' collection". In the first search the option "Populate" is executed to obtain the data of the "student" collection. Then before sending the response with the element, the populate option is performed on the "course" model and thus fill in the information of said collection.

function getCursoAlumnos(req,res){

	CursoAlumnos.find().populate({patch: 'rutalumno'}).exec((err, cursoalumno) => {
		if(err){
			res.status(500).send({message:'Error de conexión a la BD'});
		}else{
			if(!cursoalumno){
				res.status(404).send({message: 'No existe el curso'});
			}else{
				Curso.populate(cursoalumno, {path: 'codigocurso'}, (err, docingreso) => {
					
					if(err){
						res.status(500).send({message: 'Error en la peticiona la BD'});
					}else{
						res.status(200).send(cursoalumno);
					}
				});
			}
		}
	});
	
}

module.exports = {
	getCursoAlumnos
}

After performing other steps on the nodejs server to test it, this is the result with generic data

[
    {
        "_id": "59e0357117fb951fccc948bc",
        "saldo": 150000,
        "total": 150000,
        "ncontrato": "002",
        "licencia": "A1",
        "rutalumno": {
            "_id": "59d5031e00156810fc896c6b",
            "escolaridad": "universitaria",
            "actividad": "trabajador",
            "correo": "[email protected]",
            "telefono": "755656561",
            "celular": "6745544545",
            "comuna": "molina",
            "direccion": "villa",
            "nacionalidad": "chilena",
            "estadocivil": "soltero",
            "edad": 29,
            "nacimiento": "01-10-2594",
            "amaterno": "torres",
            "apaterno": "contreras",
            "nombre": "sergio",
            "rut": "16646011-5",
            "__v": 0
        },
        "codigocurso": {
            "_id": "59decd99fa96d61190d2ca12",
            "fechatermino": "10-12-2016",
            "fechainicio": "10-12-2016",
            "lugar": "curico",
            "codigocurso": "tal-cur-001",
            "__v": 0
        },
        "__v": 0
    }
]

Without the populate option it would look like this: We would obtain the data of the collection "alumni" without the reference to the data of the other colleges.

[
    {
        "_id": "59e0357117fb951fccc948bc",
        "saldo": 150000,
        "total": 150000,
        "ncontrato": "002",
        "licencia": "A1",
        "rutalumno": "59d5031e00156810fc896c6b",
        "codigocurso": "59decd99fa96d61190d2ca12",
        "__v": 0
    }
]

Hopefully it will help you because it costs me to get to the result, it is a simple code since it has no searches or specific ordering.

    
answered by 13.10.2017 в 18:21
0

There are two ways to relate documents in mongo:

  • Embedded

  • Referenced

  • Embedded is that your collection has an attribute that contains all the data of another model, example:

    {
    _id: ObjectId('...'),
    name: 'test',
    data: {
        data1: '',
        data2: 100,
        data3: [],
        dataN: {}
      }
    }
    

    And referenced using the previous example would be:

    {
    _id: ObjectId('...'),
    name: 'test',
    data: objectId('...')
    }
    

    What is the best way? It depends if your queries will be heavy and will affect the performance, for example if you only want the names, why load all the embedded info? You can say that you can make filters, but by doing that, Mongo first loads the entire document and then filters it which would be affecting the performance anyway. And well, other criteria are if the relationship of your documents is essential for your app to fulfill its function. There may be other criteria, it depends a lot on the requirements and the development team.

    If it is by reference, for queries with populate () to work, the id of the referenced document must be of the ObjectId type, otherwise, it will not work.

    The example you put:

    {id_a : '2der45g', data : 'etc'}
    

    If you have it that way, for mongo the _id is a String, not an ObjectId. It is a lot of difference because the shape of each one is based on different bytes.

    When you make your model, you must declare its type as ObjectId and indicate with which other model it refers. I'll give you an example but I'll leave you here the mongoose documentation

    var mongoose = require('mongoose')
      , Schema = mongoose.Schema
    
    var personSchema = Schema({
      _id     : Number,
      name    : String,
      age     : Number,
      stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
    });
    
    var storySchema = Schema({
      _creator : { type: Number, ref: 'Person' },
      title    : String,
      fans     : [{ type: Number, ref: 'Person' }]
    });
    
    var Story  = mongoose.model('Story', storySchema);
    var Person = mongoose.model('Person', personSchema);
    

    With that you can now use populate ():

    Story.
      findOne({ title: 'Once upon a timex.' }).
      populate('_creator').
      exec(function (err, story) {
        if (err) return handleError(err);
        console.log('The creator is %s', story._creator.name);
        // prints "The creator is Aaron"
      });
    

    On the other hand, if it is an embedded relationship, just find () and access the attribute that contains the information you want, but let's say that most of the time you want to do it by reference, it depends on your requirements and if you get to use it, there must be good reasons.

    In conclusion, check how you are declaring your models so that associating them is possible, you can use these examples to make a test and then adapt it to your models.

        
    answered by 12.08.2017 в 17:33