Tengo problemas para buscar la clave de un objeto anidado.

Tengo un objeto de criterio de búsqueda que puede o no tener ciertos campos en los que me gustaría buscar.

La forma en que estoy resolviendo esto es usar declaraciones condicionales para agregar a un objeto de "criterio de coincidencia" que se pasa al operador agregado de $ coincidencia. funciona bien hasta que necesito hacer coincidir algo dentro de un objeto anidado.

Aquí hay una estructura de documento de muestra

{
        name: string,
        dates: {
            actived: Date,
            suspended: Date
        },
        address : [{
            street: string,
            city: string,
            state: string,
            zip: string
        }]

    };

Mi objeto de criterios se completa a través de una interfaz de usuario y pasa un JSON que se parece a esto:

{
        "name": "",
        "state": ""
    }

Y aunque puedo usar explícitamente "date.suspended" sin problemas, cuando intento agregar address.state a mis criterios de búsqueda, obtengo un error.

module.exports.search = function( criteria, callback ) 

        let matchCriteria = {
            "name": criteria.name,
            "dates.suspended": null
        };


        if ( criteria.state !== '' ) {
           // *** PROBLEM HAPPENS HERE *** //
            matchCriteria.address.state = criteria.state;
        }

        User.aggregate([
            { "$match": matchCriteria },
            { "$addFields": {...} },
            { "$project": {...} }
        ], callback );

    }

Recibo el error:

TypeError: no se puede establecer la propiedad 'estado' de indefinido

Entiendo que estoy especificando 'address.state' cuando 'address' aún no existe, pero no estoy claro cuál sería mi sintaxis seguramente no sería matchCriteria ['address.state'] o "matchCriteria.address .estado"

¿Hay una mejor manera de hacer un filtrado condicional?

0
j-p 16 sep. 2018 a las 07:27

3 respuestas

La mejor respuesta

Para buscar en objetos anidados, debe usar unwind

Una consulta que lo ayudará:

// Para probar declarar criteria como constante

 let  criteria = {name : 'name', 'state' : 'state'};
 let addressMatch = {};
 let matchCriteria = {
            "name": criteria.name,
            "dates.suspended": null
        };


        if ( criteria.state) {

            addressMatch = { 'address.state' :  criteria.state };
        }

db.getCollection('user').aggregate([{
    $match :matchCriteria,
    },{$unwind:'$address'},
    {$match :  addressMatch}
    ])
2
IftekharDani 16 sep. 2018 a las 11:10

Primero verifique la dirección y luego acceda a la propiedad como se muestra:

if(matchCriteria['address']) {
 matchCriteria['address']['state'] = criteria['state'];
}
else {
//otherwise
}
0
Sagar Chaudhary 16 sep. 2018 a las 09:51

Esto debería solucionarlo:

matchCriteria['address.state'] = criteria.state;
0
scthi 16 sep. 2018 a las 09:53