วิธีกำหนดวัตถุในอาร์เรย์ใน Mongoose schema อย่างถูกต้องด้วยดัชนีภูมิศาสตร์ 2d


113

ขณะนี้ฉันมีปัญหาในการสร้างสคีมาสำหรับเอกสารด้านล่าง การตอบสนองจากเซิร์ฟเวอร์จะส่งกลับค่าฟิลด์ "trk" เป็น [Object] เสมอ ฉันไม่รู้ว่ามันควรจะทำงานอย่างไรเพราะอย่างน้อยฉันก็ลองทุกวิธีที่เข้าท่าสำหรับฉัน ;-)

หากสิ่งนี้ช่วยได้เวอร์ชัน Mongoose ของฉันคือ 3.6.20 และ MongoDB 2.4.7 และก่อนที่ฉันจะลืมมันจะเป็นการดีที่จะตั้งเป็นดัชนี (2d)

ข้อมูลต้นฉบับ:

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

พังพอน Schema:

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

การตอบสนองจากแท็บเครือข่ายใน Chrome จะมีลักษณะเช่นนี้เสมอ (นั่นเป็นเพียงส่วน trk เท่านั้นที่ไม่ถูกต้อง):

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

ฉันได้ลองใช้คำจำกัดความของสคีมาที่แตกต่างกันสำหรับ "trk" แล้ว:

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

หวังว่าคุณจะช่วยฉันได้นะ ;-)

คำตอบ:


219

คุณสามารถประกาศ trk ได้ด้วยวิธีต่อไปนี้: - อย่างใดอย่างหนึ่ง

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

หรือ

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

ในกรณีที่สองระหว่างการแทรกให้สร้างวัตถุและผลักเข้าไปในอาร์เรย์เช่น

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

หรือคุณสามารถตั้งค่าอาร์เรย์ของวัตถุโดย

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

มีแนวคิดอย่างไรในการตั้งชื่อฟิลด์ html ในกรณีเช่นนี้เช่นในกรณีที่เราต้องการจัดเก็บอาร์เรย์ของวัตถุจาวาสคริปต์ในฐานข้อมูล เช่นการตั้งชื่อฟิลด์เป็นtrk.latและtrk.lngใน html จะไม่ทำงาน
Raeesaa

3
trk: {type: Array, "default": []} เหมาะกับฉันที่สุด! เรียบง่ายและสง่างาม!
spiralmoon

1
@DpGeek หากคุณกำลังประกาศอาร์เรย์ในรูปแบบนั้นคุณจะไม่สามารถอัปเดตฟิลด์อาร์เรย์ได้โดยตรง ในการอัปเดตอาร์เรย์โดยตรงฉันใช้ {lat: String, lng: String} subschema หากคุณไม่ต้องการสิ่งอำนวยความสะดวกนั้น trk: {type: Array, "default": []} จะดีที่สุดไม่งั้นคุณต้องประกาศ subschema
Kundu

ค่าเริ่มต้นที่ไม่มีเครื่องหมายคำพูดใช้ได้ผลสำหรับฉันtrk : { type : Array , default : ['item1', 'item2'] }
Shardul

1
จะยังใช้งานได้หรือไม่ถ้าฟิลด์ 'lat' และ 'lng' ที่กำหนดเป็น Number แทนสตริง
jimijazz

63

ฉันมีปัญหาคล้ายกันกับพังพอน:

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

อันที่จริงฉันใช้ "type" เป็นชื่อคุณสมบัติในสคีมาของฉัน:

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

เพื่อหลีกเลี่ยงพฤติกรรมนั้นคุณต้องเปลี่ยนพารามิเตอร์เป็น:

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

4
ใช่ไม่ได้คิดเกี่ยวกับเรื่องนั้น นั่นช่วยแก้ปัญหาของฉันได้ก่อนที่ฉันจะเริ่มกระแทกของบนโต๊ะทำงานฮ่าฮ่าขอบคุณอีกครั้ง ฉันจะหลีกเลี่ยง 'ประเภท' ในรูปแบบพังพอนของฉันจากนี้ไป
blackops

คุณสามารถยกตัวอย่าง json ที่คุณพยายามแทรกได้หรือไม่?
owensmartin

1
หรือคุณสามารถส่งตัวเลือก typeKey ไปยังตัวสร้างสคีมาของคุณเพื่อลบล้างการประกาศประเภท
jimijazz

2

ขอบคุณสำหรับคำตอบ

ฉันลองวิธีแรก แต่ไม่มีอะไรเปลี่ยนแปลง จากนั้นฉันพยายามบันทึกผลลัพธ์ ฉันเพิ่งเจาะลึกลงไปทีละระดับจนกระทั่งในที่สุดฉันก็ไปถึงตำแหน่งที่แสดงข้อมูล

หลังจากนั้นไม่นานฉันก็พบปัญหา: เมื่อฉันส่งการตอบกลับฉันกำลังแปลงเป็นสตริงผ่าน .toString() .

ฉันแก้ไขแล้วและตอนนี้มันก็ทำงานได้อย่างยอดเยี่ยม ขออภัยสำหรับการเตือนที่ผิดพลาด


1

ปัญหาที่ฉันต้องแก้ไขคือการจัดเก็บสัญญาที่มีช่องไม่กี่ช่อง (ที่อยู่หนังสือ num_of_days ผู้ยืม_addr blk_data) blk_data คือรายการธุรกรรม (หมายเลขบล็อกและที่อยู่ธุรกรรม) คำถามและคำตอบนี้ช่วยฉันได้ ฉันต้องการแบ่งปันรหัสของฉันตามด้านล่าง หวังว่านี่จะช่วยได้

  1. ข้อกำหนดของสคีมา ดู 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. สร้างเรกคอร์ดสำหรับคอลเลกชันใน MongoDB ดู 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. อัปเดตบันทึก ดู 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));
        });
    },
];
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.