Como definir o objeto na matriz no esquema Mongoose corretamente com o índice geo 2D

113

No momento, estou tendo problemas para criar um esquema para o documento abaixo. A resposta do servidor sempre retorna os valores do campo "trk" como [Objeto]. De alguma forma, não tenho ideia de como isso deve funcionar, pois tentei pelo menos todas as abordagens que faziam sentido para mim ;-)

Se isso ajudar, minha versão do Mongoose é 3.6.20 e MongoDB 2.4.7 E antes que me esqueça, seria bom defini-lo também como Índice (2d)

Dados originais:

{
    "_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 Mongoose:

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

A resposta da guia Rede no Chrome sempre se parece com esta (é apenas a parte trk que está errada):

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

Já tentei diferentes definições de esquema para "trk":

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

Espero que possa me ajudar ;-)

niels_h
fonte

Respostas:

219

Você pode declarar trk das seguintes maneiras: - ou

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

ou

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

No segundo caso, durante a inserção, faça o objeto e empurre-o para dentro da matriz como

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

ou você pode definir a 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
fonte
alguma ideia de como nomear campos html nesse caso, ou seja, no caso de precisarmos armazenar uma matriz de objetos javascript no banco de dados? Por exemplo, nomear campos como trk.late trk.lngem html não funcionará.
Raeesaa de
3
trk: {type: Array, "default": []} funciona melhor para mim! É simples e elegante!
spiralmoon
1
@DpGeek se você estiver declarando array nesse formato, você não pode atualizar o campo array diretamente. Para atualizar a matriz diretamente, usei o subesquema {lat: String, lng: String}. Se você não quiser essa facilidade, trk: {type: Array, "default": []} será o melhor, caso contrário, você terá que declarar o subesquema.
Kundu
padrão sem aspas funcionou para mimtrk : { type : Array , default : ['item1', 'item2'] }
Shardul
1
ainda funcionaria se os campos 'lat' e 'lng' fossem definidos como Número em vez de string?
jimijazz
63

Tive um problema semelhante com o mangusto:

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

Na verdade, eu estava usando "tipo" como um nome de propriedade em meu esquema:

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

Para evitar esse comportamento, você deve alterar o parâmetro para:

fields: [
    {
      name: String,
      type: {
        type: { type: String }
      },
      registrationEnabled: Boolean,
      checkinEnabled: Boolean
    }
  ]
Pierre Maoui
fonte
4
inferno, sim, nem sequer pensei nisso. Isso resolveu meu problema pouco antes de eu começar a jogar coisas na minha mesa haha, obrigado novamente. Vou apenas evitar 'digitar' em meus esquemas de mangusto de agora em diante.
blackops em
Você pode dar um exemplo do json que estava tentando inserir?
owensmartin
1
ou você pode passar a opção typeKey para o seu construtor de esquema para substituir a declaração de tipo
jimijazz
2

Obrigado pelas respostas.

Tentei a primeira abordagem, mas nada mudou. Então, tentei registrar os resultados. Eu apenas analisei nível por nível, até que finalmente cheguei onde os dados estavam sendo exibidos.

Depois de um tempo, descobri o problema: quando estava enviando a resposta, estava convertendo para uma string via .toString().

Consertei isso e agora funciona perfeitamente. Desculpe pelo alarme falso.

niels_h
fonte
1

O problema que preciso resolver é armazenar contratos contendo alguns campos (endereço, livro, num_of_days, borrower_addr, blk_data), blk_data é uma lista de transações (número do bloco e endereço da transação). Esta pergunta e resposta me ajudaram. Eu gostaria de compartilhar meu código conforme abaixo. Espero que isto ajude.

  1. Definição de esquema. Veja 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. Crie um registro para a coleção no MongoDB. Veja 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. Atualize um registro. Veja 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));
        });
    },
];
GoodApple
fonte