简体   繁体   English

如何使用 2d 地理索引在 Mongoose 模式中正确定义数组中的对象

[英]How to define object in array in Mongoose schema correctly with 2d geo index

I'm currently having problems in creating a schema for the document below.我目前在为以下文档创建架构时遇到问题。 The response from the server always returns the "trk" field values as [Object].来自服务器的响应总是将“trk”字段值返回为 [Object]。 Somehow I have no idea how this should work, as I tried at least all approaches which made sense to me ;-)不知何故,我不知道这应该如何工作,因为我至少尝试了所有对我有意义的方法;-)

If this helps, my Mongoose version is 3.6.20 and MongoDB 2.4.7 And before I forget, it would be nice to also set it as Index (2d)如果这有帮助,我的 Mongoose 版本是 3.6.20 和 MongoDB 2.4.7 在我忘记之前,最好也将其设置为 Index (2d)

Original data:原始数据:

{
    "_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
    }]
    }
}

Mongoose Schema:猫鼬模式:

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

The response from the Network tab in Chrome always looks like this (that's only the trk-part which is wrong) : Chrome 中网络选项卡的响应总是如下所示(这只是错误的 trk 部分):

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

I already tried different Schema definitions for "trk":我已经为“trk”尝试了不同的模式定义:

  1. trk: Schema.Types.Mixed trk:Schema.Types.Mixed
  2. trk: [Schema.Types.Mixed] trk:[Schema.Types.Mixed]
  3. trk:[ { type:[Number], index: "2d" }] trk:[ { type:[Number], index: "2d" }]

Hope you can help me ;-)希望你能帮我 ;-)

You can declare trk by the following ways : - either您可以通过以下方式声明 trk : - 要么

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

or或者

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

In the second case during insertion make the object and push it into the array like在插入期间的第二种情况下,制作对象并将其推入数组中

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

or you can set the Array of object by或者您可以设置对象数组

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'
      }
});

I had a similar issue with mongoose :我对 mongoose 有类似的问题:

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

In fact, I was using "type" as a property name in my schema :事实上,我在架构中使用“类型”作为属性名称:

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

To avoid that behavior, you have to change the parameter to :为避免这种行为,您必须将参数更改为:

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

For making an array in schema we have to make one more schema as monetizationSchema which is used to store one data at a time and another as blogSchema we have monetization field containing monetizationSchema in square brackets as an array.为了在模式中创建一个数组,我们必须再创建一个模式作为monetizationSchema ,它用于一次存储一个数据,另一个作为blogSchema ,我们在方括号中包含monetizationSchema作为数组的monetization字段。

Schema for storing one data at a time.一次存储一个数据的Schema

const monetizationSchema = new Schema({
      amazonUrl: {
        type: String,
        required: true,
      } 
    });

Schema with monetization as an array.以数组形式monetization的架构。

const blogSchema = {
  monetization: [
   monetizationSchema
  ],
  image: {
   type: String,
   required: true
  },
  // ... etc
});

The problem I need to solve is to store contracts containing a few fields (address, book, num_of_days, borrower_addr, blk_data), blk_data is a transaction list (block number and transaction address).我需要解决的问题是存储包含几个字段(address、book、num_of_days、borrower_addr、blk_data)的合约,blk_data 是一个交易列表(区块号和交易地址)。 This question and answer helped me.这个问题和答案帮助了我。 I would like to share my code as below.我想分享我的代码如下。 Hope this helps.希望这可以帮助。

  1. Schema definition.架构定义。 See blk_data.请参见 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. Create a record for the collection in the MongoDB.在 MongoDB 中为集合创建一条记录。 See blk_data.请参见 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. Update a record.更新记录。 See blk_data.请参见 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));
        });
    },
];

Thanks for the replies.感谢您的回复。

I tried the first approach, but nothing changed.我尝试了第一种方法,但没有任何改变。 Then, I tried to log the results.然后,我尝试记录结果。 I just drilled down level by level, until I finally got to where the data was being displayed.我只是逐级向下钻取,直到最终到达显示数据的位置。

After a while I found the problem: When I was sending the response, I was converting it to a string via .toString() .过了一会儿,我发现了问题:当我发送响应时,我通过.toString()将其转换为字符串。

I fixed that and now it works brilliantly.我解决了这个问题,现在它工作得很好。 Sorry for the false alarm.很抱歉误报。

You can declare an array as below您可以如下声明一个数组

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

but it will set [] (empty array) as the default value.但它会将[] (空数组)设置为默认值。

If you don't want this default value then to overwrite this default, you need to set the default value to undefined as below如果你不想要这个默认值然后覆盖这个默认值,你需要将默认值设置为undefined如下

trk: {
    type: [{
        lat : String,
        lng : String
    }],
    default: undefined
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM