2D 지리적 인덱스를 사용하여 Mongoose 스키마의 배열에서 객체를 올바르게 정의하는 방법


113

현재 아래 문서에 대한 스키마를 만드는 데 문제가 있습니다. 서버의 응답은 항상 "trk"필드 값을 [Object]로 반환합니다. 적어도 나에게 의미가있는 모든 접근 방식을 시도했기 때문에 어떻게 든 이것이 어떻게 작동해야하는지 전혀 모르겠습니다 ;-)

이것이 도움이된다면 내 Mongoose 버전은 3.6.20이고 MongoDB 2.4.7이고 잊어 버리기 전에 Index (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
    }]
    }
}

몽구스 스키마 :

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 : [{유형 : [번호], 인덱스 : "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 필드의 이름을 지정하는 방법, 즉 데이터베이스에 javascript 객체 배열을 저장해야하는 경우에 어떤 아이디어가 있습니까? 예를 들어 이름 지정 필드 trk.lattrk.lnghtml이 작동하지 않습니다.
Raeesaa 2014

3
trk : {type : Array, "default": []} 가장 잘 작동합니다! 간단하고 우아합니다!
spiralmoon 2014.06.02

1
@DpGeek 해당 형식으로 배열을 선언하는 경우 배열 필드를 직접 업데이트 할 수 없습니다. 배열을 직접 업데이트하기 위해 {lat : String, lng : String} 하위 스키마를 사용했습니다. 해당 기능을 원하지 않는 경우 trk : {type : Array, "default": []}가 가장 좋습니다. 그렇지 않으면 하위 스키마를 선언해야합니다.
kundu를

따옴표가없는 기본값이 나를 위해 일했습니다trk : { type : Array , default : ['item1', 'item2'] }
Shardul

1
문자열 대신 숫자로 정의 된 'lat'및 'lng'필드가 여전히 작동합니까?
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
그래, 그것에 대해 생각조차하지 않았다. 내 책상에 물건을 치기 시작하기 직전에 문제가 해결되었습니다. haha ​​다시 감사드립니다. 이제부터는 몽구스 스키마에서 '유형'을 피할 것입니다.
blackops 2015 년

삽입하려는 json의 예를 들어 줄 수 있습니까?
owensmartin 2015 년

1
또는 당신은 형식 선언 오버라이드 (override)하는 스키마 빌더로 typeKey 옵션을 전달할 수
jimijazz

2

답장을 보내 주셔서 감사합니다.

첫 번째 접근 방식을 시도했지만 아무것도 바뀌지 않았습니다. 그런 다음 결과를 기록하려고했습니다. 마지막으로 데이터가 표시되는 위치에 도달 할 때까지 수준별로 드릴 다운했습니다.

잠시 후 문제를 발견했습니다. 응답을 보낼 때 .NET을 통해 문자열로 변환했습니다 .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.