Простая схема Meteor для геолокационных данных mongo

#mongodb #meteor #schema

#mongodb #meteor #схема

Вопрос:

Я хочу создать форму администратора для своего приложения meteor; Я собирался попробовать Ogno Admin, прежде чем прибегать к созданию с нуля, но я не уверен, сможет ли он поддерживать данные в нужном мне формате. Мои текущие данные приложения поступают в mongo следующим образом:

 Beaches.insert({
    "name": "Entry name",
    /* location stored like this so I can use mongo $near queries */
    "location": {
        "type": "Point",
        "coordinates": [-5.0990296,50.110757]
    },
    /* could be many images, minimum 1 */
    "images": [
        {
            "url": "image1.jpg",
            "caption": "Image caption"
        }
    ],
    "shortDesc": "A delightful description...",
    /* fixed list of attributes stored as objects */
    "attributes": {
        "attr 1": {
            "score": 2,
            "text": "attr1 text"
        },
  

Могу ли я написать простую схему для поддержки различных массивов / объектов выше (особенно координат местоположения)? Они должны быть в формате квадратных скобок [lng, lat] — и будет ли ogno admin работать с этим, или мне придется писать пользовательские данные администратора? Возможно, мне было бы проще создать сайт администратора в чем-то другом и заставить его выводить данные JSON для Meteor.

Обновление с возможным кодом схемы

 Beaches = new SimpleSchema({
  name: {
    type: String,
  },
  location: {
    type: [Object]
  },
    location.$.type: {
    /* how do I force '"type" : "Point" into every entry?
       use 'autovalue' with the .clean() function?*/
    },
      location.$.coordinates: {
      /* how do I ensure a [x,y] array in here? */
    },
  images: {
    type: [Object]
  },
    "images.$.url": {
        type: String
    },
    "images.$.caption": {
        type: String
    },
  attributes: {
    type: [Object]
  },
  /* note that my attributes above are all prefixed with a 'name'
     eg. "attr 1" : {}
     I'm not sure how to declare these either!
  */
  ...
});
  

Комментарии:

1. Да, простая схема работает с координатами местоположения. Есть ли у вас какие-либо усилия? Я не знаю администратора Ogno, но в документах написано, что они проверяют с помощью simple-schema, поэтому он должен работать с простой схемой.

2. Я просто не уверен, как форматировать местоположение — особенно массив координат — я не хочу добавлять к данным префиксы «lng» и «lat», а простая схема не имеет типа «Массив» (только строка, число, логическое значение и объект)

3. Простая схема имеет тип массива. [object] Перейдите сюда ( github.com/aldeed/meteor-simple-schema ) и выполните поиск «Для указания наличия массива».

Ответ №1:

Хм, я точно не знаю, как решить ваш процесс сохранения географических координат. Но если вы хотите сохранить lng и lat, вам нужно передать префикс. Почему? Ну, геокорды имеют разные диапазоны проверки. Широта доступна только от -90 до 90, а долгота от -180 до 180. Если вы не сохраните префикс, как вы хотите убедиться, какая из координат какая? Еще один совет, который я когда-нибудь сделал false, — сохранить координаты в порядке долготы и широты.

Схема, которую я использую, выглядит следующим образом:

 GeocoordsSchema = new SimpleSchema({
  lng: {
    type : Number,
    decimal: true,
    min: -180,
    max: 180
  }, 
  lat: {
    type : Number,
    decimal: true,
    min: -90,
    max: 90
  }
});
  

Теперь вы создаете вложенные схемы. Просто расширьте GeocoordsSchema с помощью LocationSchema и добавьте атрибут.

 LocationSchema = new SimpleSchema({
  type : {
    type : String,
    autoValue: function() {
      return "Point";
    }
  },
  coordinate: {
    type: GeocoordsSchema 
  }
});
  

Если вы хотите иметь массив LocationSchema, вы можете заключить схему в скобки [].

 BeachesSchema = new SimpleSchema({
  loc: {
    type: [LocationSchema]
  }
});
  

Я не тестировал, но именно так я создаю и внедряю разные схемы. Ну, для этого решения нужен идентификатор lat и lng. Почему вы не хотите указывать префикс своих данных?

Комментарии:

1. Это здорово, большое спасибо chaosborne. Я не думал, что хочу добавлять префикс к своим координатам latlng, потому что моя текущая рабочая схема (возможно, ошибочно) основана на поиске $ near, описанном в документах mongo, но ваш код выглядит действительно хорошо, поэтому сегодня утром я попробую изменить свои данные, чтобы посмотреть, смогу ли я заставить его работать таким образом!

2. Это выглядит как отличный ответ — даст ему шанс.

3. Протестировано и, похоже, не работает с индексом 2ds. Просто GeocoordsSchema — это объект, а не массив чисел.

Ответ №2:

Мое решение похоже на решение chaosbohne, но я определяю все местоположение с помощью одной подсхемы и некоторых пользовательских проверок, подобных этому:

 SimpleSchema.messages
  lonOutOfRange: '[label] longitude should be between -90 and 90'
  latOutOfRange: '[label] latitude should be between -180 and 180'

LocationSchema = new SimpleSchema
  type:
    type: String,
    allowedValues: ['Point']
  coordinates:
    type: [Number]
    decimal: true
    minCount: 2
    maxCount: 2
    custom: ->
      return "lonOutOfRange" unless -90 <= @value[0] <= 90
      return "latOutOfRange" unless -180 < @value[1] <= 180
  

Там, где это возможно, я использую существующие функции проверки SimpleSchema. Координаты ограничены с помощью minCount и maxCount , хотя я мог бы также использовать другую строку в пользовательской функции проверки. Что-то вроде этого:

 SimpleSchema.messages
  needsLatLong: '[label] should be of form [longitude, latitude]'
  lonOutOfRange: '[label] longitude should be between -90 and 90'
  latOutOfRange: '[label] latitude should be between -180 and 180'

LocationSchema = new SimpleSchema
  type:
    type: String,
    allowedValues: ['Point']
  coordinates:
    type: [Number]
    decimal: true
    custom: ->
      return "needsLatLong" unless @value.length is 2
      return "lonOutOfRange" unless -90 <= @value[0] <= 90
      return "latOutOfRange" unless -180 < @value[1] <= 180
  

Теперь в вашем примере вы бы написали:

 Beaches = new SimpleSchema
  name:
    type: String
  location:
    type: LocationSchema
    index: '2dsphere'
  images:
    type: [Object]
  "images.$.url":
    type: String
  "images.$.caption":
    type: String
  attributes:
    type: [Object]
  

Обратите index: '2dsphere' внимание, чтобы MongoDB знал о типе индекса.

Комментарии:

1. Потрясающе, спасибо, что поделились этим! Следует ли переключать индексы lat и lon, поскольку Mongo говорит: «Всегда сохраняйте координаты в порядке долготы и широты».?

2. Спасибо! Вы правы, это была опечатка в сообщении проверки. Исправлено. 🙂

3. Также необходимо переключиться на то, чтобы сначала указать lon в custom: validations, чтобы lonOutOfRange проверял @value[0], верно?

Ответ №3:

Возможно, OP уже решил эту проблему, но я все же хотел бы опубликовать свой ответ, чтобы вернуть немного любви сообществу StackOverflow.

Прежде всего, создайте PlaceSchema следующим образом:

 LocationSchema = new SimpleSchema({
    "type":{
        type: String,
        allowedValues: ["Point"]
    },
    "coordinates":{
        type: Array,
        minCount: 2,
        maxCount: 2
    },
    "coordinates.$":{
        type: Number,
        decimal: true,
        custom: function(){
            if(!(-90 <= this.value[0] <= 90))
                return "lonOutOfRange" ;
            if(!(-180 <= this.value[1] <= 180))
                return "latOutOfRange" ;
        }

    },
    "name": {
        type: String,
        optional: true
    },
});



LocationSchema.messages = {
  lonOutOfRange: 'Longitude out of range', // Must be between -90 and 90
  latOutOfRange: 'Latitude out of range' // Must be between -180 and 180
}
  

Теперь используйте его внутри своей основной схемы:

 BeachSchema = new SimpleSchema({
    name: {
        type: String,
    },
    location: {
        type: LocationSchema // HERE
    }
    // ...
});
  

Затем присоедините схему к своей коллекции:

 Beaches.attachSchema(BeachSchema);//*/
  

Вы также можете рассмотреть возможность добавления 2dsphere индекса с помощью:

 Beaches._ensureIndex({ "location": "2dsphere"});