Cómo definir el objeto en la matriz en el esquema de Mongoose correctamente con 2d geo index

113

Actualmente tengo problemas para crear un esquema para el siguiente documento. La respuesta del servidor siempre devuelve los valores del campo "trk" como [Objeto]. De alguna manera, no tengo idea de cómo debería funcionar esto, ya que probé al menos todos los enfoques que tenían sentido para mí ;-)

Si esto ayuda, mi versión de Mongoose es 3.6.20 y MongoDB 2.4.7 Y antes de que me olvide, sería bueno configurarlo también como Index (2d)

Datos originales:

{
    "_id": ObjectId("51ec4ac3eb7f7c701b000000"),
    "gpx": {
        "metadata": {
            "desc": "Nürburgring VLN-Variante",
            "country": "de",
            "isActive": true
        },
    "trk": [
    {
        "lat": 50.3299594,
        "lng": 6.9393006
    },
    {
        "lat": 50.3295046,
        "lng": 6.9390688
    },
    {
        "lat": 50.3293714,
        "lng": 6.9389939
    },
    {
        "lat": 50.3293284,
        "lng": 6.9389634
    }]
    }
}

Esquema de la mangosta:

var TrackSchema = Schema({
            _id: Schema.ObjectId,
            gpx: {
                metadata: {
                    desc: String,
                    country: String,
                    isActive: Boolean
                },
                trk: [{lat:Number, lng:Number}]
            }
        }, { collection: "tracks" });

La respuesta de la pestaña Red en Chrome siempre se ve así (esa es solo la parte trk que está mal):

{ trk: 
      [ [Object],
        [Object],
        [Object],
        [Object],
        [Object],
        [Object],

Ya probé diferentes definiciones de esquema para "trk":

  1. trk: Schema.Types.Mixed
  2. trk: [Schema.Types.Mixed]
  3. trk: [{tipo: [Número], índice: "2d"}]

Espero que puedas ayudarme ;-)

niels_h
fuente

Respuestas:

219

Puede declarar trk de las siguientes formas: - ya sea

trk : [{
    lat : String,
    lng : String
     }]

o

trk : { type : Array , "default" : [] }

En el segundo caso, durante la inserción, haga el objeto y empújelo en la matriz como

db.update({'Searching criteria goes here'},
{
 $push : {
    trk :  {
             "lat": 50.3293714,
             "lng": 6.9389939
           } //inserted data is the object to be inserted 
  }
});

o puede establecer la matriz de objeto por

db.update ({'seraching criteria goes here ' },
{
 $set : {
          trk : [ {
                     "lat": 50.3293714,
                     "lng": 6.9389939
                  },
                  {
                     "lat": 50.3293284,
                     "lng": 6.9389634
                  }
               ]//'inserted Array containing the list of object'
      }
});
Kundu
fuente
¿Alguna idea de cómo nombrar los campos html en tal caso, es decir, en caso de que necesitemos almacenar una matriz de objetos javascript en la base de datos? Por ejemplo, nombrar campos como trk.laty trk.lngen html no funcionará.
Raeesaa
3
trk: {type: Array, "default": []} funciona mejor para mí. ¡Es simple y elegante!
Spiralmoon
1
@DpGeek si está declarando una matriz en ese formato, no puede actualizar el campo de la matriz directamente. Para actualizar la matriz directamente utilicé el subesquema {lat: String, lng: String}. Si no desea esa función, entonces trk: {type: Array, "default": []} será el mejor; de lo contrario, debe declarar el subesquema.
Kundu
predeterminado sin comillas funcionó para mítrk : { type : Array , default : ['item1', 'item2'] }
Shardul
1
¿Seguiría funcionando si los campos 'lat' y 'lng' estuvieran definidos como Número en lugar de cadena?
jimijazz
63

Tuve un problema similar con la mangosta:

fields: 
    [ '[object Object]',
     '[object Object]',
     '[object Object]',
     '[object Object]' ] }

De hecho, estaba usando "tipo" como nombre de propiedad en mi esquema:

fields: [
    {
      name: String,
      type: {
        type: String
      },
      registrationEnabled: Boolean,
      checkinEnabled: Boolean
    }
  ]

Para evitar ese comportamiento, debe cambiar el parámetro a:

fields: [
    {
      name: String,
      type: {
        type: { type: String }
      },
      registrationEnabled: Boolean,
      checkinEnabled: Boolean
    }
  ]
Pierre Maoui
fuente
4
diablos, sí, ni siquiera pensé en eso. Eso resolvió mi problema justo antes de que estuviera a punto de comenzar a golpear mi escritorio jaja gracias de nuevo. Voy a evitar el "tipo" en mis esquemas de mangosta a partir de ahora.
Blackops
¿Puede dar un ejemplo del json que intentaba insertar?
owensmartin
1
o puede pasar la opción typeKey a su generador de esquemas para anular la declaración de tipo
jimijazz
2

Gracias por las respuestas.

Probé el primer enfoque, pero nada cambió. Luego, intenté registrar los resultados. Simplemente profundicé nivel por nivel, hasta que finalmente llegué al lugar donde se mostraban los datos.

Después de un tiempo encontré el problema: cuando estaba enviando la respuesta, la estaba convirtiendo en una cadena a través de .toString().

Lo arreglé y ahora funciona de manera brillante. Disculpa por la falsa alarma.

niels_h
fuente
1

El problema que necesito resolver es almacenar contratos que contengan algunos campos (dirección, libro, num_of_days, prestatario_addr, blk_data), blk_data es una lista de transacciones (número de bloque y dirección de transacción). Esta pregunta y respuesta me ayudaron. Me gustaría compartir mi código de la siguiente manera. Espero que esto ayude.

  1. Definición de esquema. Ver blk_data.
var ContractSchema = new Schema(
    {
        address: {type: String, required: true, max: 100},  //contract address
        // book_id: {type: String, required: true, max: 100},  //book id in the book collection
        book: { type: Schema.ObjectId, ref: 'clc_books', required: true }, // Reference to the associated book.
        num_of_days: {type: Number, required: true, min: 1},
        borrower_addr: {type: String, required: true, max: 100},
        // status: {type: String, enum: ['available', 'Created', 'Locked', 'Inactive'], default:'Created'},

        blk_data: [{
            tx_addr: {type: String, max: 100}, // to do: change to a list
            block_number: {type: String, max: 100}, // to do: change to a list
        }]
    }
);
  1. Cree un registro para la colección en MongoDB. Ver blk_data.
// Post submit a smart contract proposal to borrowing a specific book.
exports.ctr_contract_propose_post = [

    // Validate fields
    body('book_id', 'book_id must not be empty.').isLength({ min: 1 }).trim(),
    body('req_addr', 'req_addr must not be empty.').isLength({ min: 1 }).trim(),
    body('new_contract_addr', 'contract_addr must not be empty.').isLength({ min: 1 }).trim(),
    body('tx_addr', 'tx_addr must not be empty.').isLength({ min: 1 }).trim(),
    body('block_number', 'block_number must not be empty.').isLength({ min: 1 }).trim(),
    body('num_of_days', 'num_of_days must not be empty.').isLength({ min: 1 }).trim(),

    // Sanitize fields.
    sanitizeBody('*').escape(),
    // Process request after validation and sanitization.
    (req, res, next) => {

        // Extract the validation errors from a request.
        const errors = validationResult(req);
        if (!errors.isEmpty()) {
            // There are errors. Render form again with sanitized values/error messages.
            res.status(400).send({ errors: errors.array() });
            return;
        }

        // Create a Book object with escaped/trimmed data and old id.
        var book_fields =
            {
                _id: req.body.book_id, // This is required, or a new ID will be assigned!
                cur_contract: req.body.new_contract_addr,
                status: 'await_approval'
            };

        async.parallel({
            //call the function get book model
            books: function(callback) {
                Book.findByIdAndUpdate(req.body.book_id, book_fields, {}).exec(callback);
            },
        }, function(error, results) {
            if (error) {
                res.status(400).send({ errors: errors.array() });
                return;
            }

            if (results.books.isNew) {
                // res.render('pg_error', {
                //     title: 'Proposing a smart contract to borrow the book',
                //     c: errors.array()
                // });
                res.status(400).send({ errors: errors.array() });
                return;
            }

            var contract = new Contract(
                {
                    address: req.body.new_contract_addr,
                    book: req.body.book_id,
                    num_of_days: req.body.num_of_days,
                    borrower_addr: req.body.req_addr

                });

            var blk_data = {
                    tx_addr: req.body.tx_addr,
                    block_number: req.body.block_number
                };
            contract.blk_data.push(blk_data);

            // Data from form is valid. Save book.
            contract.save(function (err) {
                if (err) { return next(err); }
                // Successful - redirect to new book record.
                resObj = {
                    "res": contract.url
                };
                res.status(200).send(JSON.stringify(resObj));
                // res.redirect();
            });

        });

    },
];
  1. Actualiza un registro. Ver blk_data.
// Post lender accept borrow proposal.
exports.ctr_contract_propose_accept_post = [

    // Validate fields
    body('book_id', 'book_id must not be empty.').isLength({ min: 1 }).trim(),
    body('contract_id', 'book_id must not be empty.').isLength({ min: 1 }).trim(),
    body('tx_addr', 'tx_addr must not be empty.').isLength({ min: 1 }).trim(),
    body('block_number', 'block_number must not be empty.').isLength({ min: 1 }).trim(),

    // Sanitize fields.
    sanitizeBody('*').escape(),
    // Process request after validation and sanitization.
    (req, res, next) => {

        // Extract the validation errors from a request.
        const errors = validationResult(req);
        if (!errors.isEmpty()) {
            // There are errors. Render form again with sanitized values/error messages.
            res.status(400).send({ errors: errors.array() });
            return;
        }

        // Create a Book object with escaped/trimmed data
        var book_fields =
            {
                _id: req.body.book_id, // This is required, or a new ID will be assigned!
                status: 'on_loan'
            };

        // Create a contract object with escaped/trimmed data
        var contract_fields = {
            $push: {
                blk_data: {
                    tx_addr: req.body.tx_addr,
                    block_number: req.body.block_number
                }
            }
        };

        async.parallel({
            //call the function get book model
            book: function(callback) {
                Book.findByIdAndUpdate(req.body.book_id, book_fields, {}).exec(callback);
            },
            contract: function(callback) {
                Contract.findByIdAndUpdate(req.body.contract_id, contract_fields, {}).exec(callback);
            },
        }, function(error, results) {
            if (error) {
                res.status(400).send({ errors: errors.array() });
                return;
            }

            if ((results.book.isNew) || (results.contract.isNew)) {
                res.status(400).send({ errors: errors.array() });
                return;
            }

            var resObj = {
                "res": results.contract.url
            };
            res.status(200).send(JSON.stringify(resObj));
        });
    },
];
Buena manzana
fuente