英文:
How do I do geospatial queries using IBM Databases for MongoDB using Node.js?
问题
你可以使用MongoDB来执行此查询,以查找与给定的GeoJSON风暴对象相交的美国州份。
英文:
I have collection GeoJSON locations that represent US states. How can I find which states intersect a hypothetical storm which is also a GeoJSON object? Can MongoDB perform this query?
答案1
得分: 3
以下是翻译好的代码部分:
首先,我们需要一个包含美国各州的MongoDB集合,以GeoJSON格式存储,例如 https://github.com/glynnbird/usstatesgeojson。我们可以使用一个Node.js脚本将数据导入到新的MongoDB数据库/集合中:
// 连接凭据
const MONGO_DB = process.env.MONGO_DB
const MONGO_COLLECTION = process.env.MONGO_COLLECTION
const MONGO_URI = process.env.MONGO_URI
const MONGO_CERT_FILE = process.env.MONGO_CERT_FILE
if (!MONGO_DB || !MONGO_COLLECTION || !MONGO_URI || !MONGO_CERT_FILE) {
  console.error('缺少MONGO配置')
  process.exit(1)
}
// 常量
const DATA_DIR = './locations';
// 导入依赖项
const fs = require('fs')
const path = require('path')
const mongodb = require('mongodb')
const main = async () => {
  // 连接到MongoDB
  const MongoClient = mongodb.MongoClient
  const opts = {
    tls: true,
    tlsCAFile: MONGO_CERT_FILE,
    useUnifiedTopology: true,
    useNewUrlParser: true
  }
  const mongoClient = new MongoClient(MONGO_URI, opts)
  await mongoClient.connect()
  // 创建数据库和集合
  const db = await mongoClient.db(MONGO_DB)
  const collection = db.collection(MONGO_COLLECTION)
  // 获取要导入的数据文件列表
  const files = fs.readdirSync(DATA_DIR)
  for(const f of files) {
    const contents = fs.readFileSync(path.join(DATA_DIR, f), { encoding: 'utf8' })
    const obj = JSON.parse(contents)
    await collection.insertOne(obj)
    console.log('已插入', obj._id)
  }
  // 创建地理空间索引
  await collection.createIndex( { geometry: "2dsphere" } )
  console.log('已创建地理空间索引')
  
  // 退出
  process.exit()
}
main()
这个脚本期望您的MongoDB服务的凭据存储在环境变量中:
MONGO_DB- 数据库名称MONGO_COLLECTION- 集合名称MONGO_URI- URLMONGO_CERT_FILE- CA证书的路径
您可以从IBM Cloud仪表板获取服务的URL和证书。
脚本在名为 "locations" 的目录中查找GeoJSON文件,并将它们插入由环境变量指定的数据库/集合中。
它还指示MongoDB在数据的 "geometry" 属性上创建一个地理空间索引:
await collection.createIndex( { geometry: "2dsphere" } )
这表示"在存储在 'geometry' 属性中的数据上创建一个 '2dsphere' 索引"。
现在我们已准备好查询集合。
我们需要候选的天气事件,以GeoJSON格式表示,例如:
请注意,这场风暴涵盖了四个美国州。
查询代码如下,使用与第一个脚本相同的环境变量:
// 连接凭据
const MONGO_DB = process.env.MONGO_DB
const MONGO_COLLECTION = process.env.MONGO_COLLECTION
const MONGO_URI = process.env.MONGO_URI
const MONGO_CERT_FILE = process.env.MONGO_CERT_FILE
if (!MONGO_DB || !MONGO_COLLECTION || !MONGO_URI || !MONGO_CERT_FILE) {
  console.error('缺少MONGO配置')
  process.exit(1)
}
// 导入依赖项
const fs = require('fs')
const mongodb = require('mongodb')
const main = async () => {
  // 连接到MongoDB
  const MongoClient = mongodb.MongoClient
  const opts = {
    tls: true,
    tlsCAFile: MONGO_CERT_FILE,
    useUnifiedTopology: true,
    useNewUrlParser: true
  }
  const mongoClient = new MongoClient(MONGO_URI, opts)
  await mongoClient.connect()
  // 配置数据库和集合
  const db = await mongoClient.db(MONGO_DB)
  const collection = db.collection(MONGO_COLLECTION)
  
  // 这是我们的输入天气事件
  const data = fs.readFileSync('./storm.geojson', { encoding: 'utf8' })
  const storm = JSON.parse(data)
  // 查找受风暴影响的位置
  const results = await collection.find({
    geometry: {
      '$geoIntersects' : {
        '$geometry': {
          type: storm.geometry.type,
          coordinates: storm.geometry.coordinates
        }
      }
    }
  }).toArray()
  
  // 输出位置id列表
  console.log(results.map((r) => { return r._id }))
  // 退出
  process.exit()
}
main()
它从 storm.json 中加载候选的天气事件:
{"type":"Feature","properties":{},"geometry":{"coordinates":[[[-77.00416876685775,34.60867695038871],[-78.93776251685789,35.1134983061437],[-80.99220587623299,35.158420777504745],[-83.65089728248286,34.671948926428996],[-83.85963751685802,33.891272054223364],[-83.84865118873311,32.010746736868654],[-83.31032111060784,31.309406168163207],[-82.45338751685738,30.6311690732732],[-80.15724493873236,30.385070283872437],[-79.03663946998299,30.49873173190622],[-77.44362189185789,31.674764007288985],[-76.56471564185757,33.029728245050364],[-76.64161993873286,33.69040245253204],[-77.00416876685775,34.60867695038871]]],"type":"Polygon"}}
然后使用MongoDB执行地理空间查询:
  const results = await collection.find({
    geometry: {
      '$geoIntersects' : {
        '$geometry': {
          type: storm.geometry.type,
          coordinates: storm.geometry.coordinates
        }
      }
    }
  }).toArray()
这转化为"查找其 'geometry' 字段与风暴的几何图形相交的文档"。
脚本输出四个结果:
[ '南卡罗来纳',
<details>
<summary>英文:</summary>
First we need a MongoDB collection that contains the US states as GeoJSON e..g https://github.com/glynnbird/usstatesgeojson. We can import the data into a new MongoDB database/collection using a Node.js script:
```js
// connection credentials
const MONGO_DB = process.env.MONGO_DB
const MONGO_COLLECTION = process.env.MONGO_COLLECTION
const MONGO_URI = process.env.MONGO_URI
const MONGO_CERT_FILE = process.env.MONGO_CERT_FILE
if (!MONGO_DB || !MONGO_COLLECTION || !MONGO_URI || !MONGO_CERT_FILE) {
  console.error('Missing MONGO configuration')
  process.exit(1)
}
// constants
const DATA_DIR = './locations'
// import dependencies
const fs = require('fs')
const path = require('path')
const mongodb = require('mongodb')
const main = async () => {
  // connect to MongoDB
  const MongoClient = mongodb.MongoClient
  const opts = {
    tls: true,
    tlsCAFile: MONGO_CERT_FILE,
    useUnifiedTopology: true,
    useNewUrlParser: true
  }
  const mongoClient = new MongoClient(MONGO_URI, opts)
  await mongoClient.connect()
  // create db and collection
  const db = await mongoClient.db(MONGO_DB)
  const collection = db.collection(MONGO_COLLECTION)
  // get a list of data files to import
  const files = fs.readdirSync(DATA_DIR)
  for(const f of files) {
    const contents = fs.readFileSync(path.join(DATA_DIR, f), { encoding: 'utf8' })
    const obj = JSON.parse(contents)
    await collection.insertOne(obj)
    console.log('Inserted', obj._id)
  }
  // create geospatial index
  await collection.createIndex( { geometry: "2dsphere" } )
  console.log('created geospatial index')
  
  // exit
  process.exit()
}
main()
This script expects your MongoDB service's credentials to be in environment variables:
MONGO_DB- the database nameMONGO_COLLECTION- collection nameMONGO_URI- the URLMONGO_CERT_FILE- the path of the CA certificate
> You can obtain your service's URL and certificate from the IBM Cloud dashboard.
The script looks for the GeoJSON files in a directory called "locations" and inserts them into a database/collection specified by the environment variables.
It also instructs MongoDB to create a geospatial index on the data's "geometry" attribute:
await collection.createIndex( { geometry: "2dsphere" } )
This says "create a '2dsphere' index on the data stored in the 'geometry' attribute".
We are now ready to query the collection.
We need candidate weather event, expressed as GeoJSON e.g.
> Notice that the storm overlaps four US states.
The query code is as follows and uses the same environment variables as the first script:
// connection credentials
const MONGO_DB = process.env.MONGO_DB
const MONGO_COLLECTION = process.env.MONGO_COLLECTION
const MONGO_URI = process.env.MONGO_URI
const MONGO_CERT_FILE = process.env.MONGO_CERT_FILE
if (!MONGO_DB || !MONGO_COLLECTION || !MONGO_URI || !MONGO_CERT_FILE) {
  console.error('Missing MONGO configuration')
  process.exit(1)
}
// import dependencies
const fs = require('fs')
const mongodb = require('mongodb')
const main = async () => {
  // connect to MongoDB
  const MongoClient = mongodb.MongoClient
  const opts = {
    tls: true,
    tlsCAFile: MONGO_CERT_FILE,
    useUnifiedTopology: true,
    useNewUrlParser: true
  }
  const mongoClient = new MongoClient(MONGO_URI, opts)
  await mongoClient.connect()
  // configure db and collection
  const db = await mongoClient.db(MONGO_DB)
  const collection = db.collection(MONGO_COLLECTION)
  
  // this is our incoming weather event
  const data = fs.readFileSync('./storm.geojson', { encoding: 'utf8' })
  const storm = JSON.parse(data)
  // find which locations are affected by the storm
  const results = await collection.find({
    geometry: {
      '$geoIntersects' : {
        '$geometry': {
          type: storm.geometry.type,
          coordinates: storm.geometry.coordinates
        }
      }
    }
  }).toArray()
  
  // output the list of location ids
  console.log(results.map((r) => { return r._id }))
  // die
  process.exit()
}
main()
It loads the candidate weather event from storm.json:
{"type":"Feature","properties":{},"geometry":{"coordinates":[[[-77.00416876685775,34.60867695038871],[-78.93776251685789,35.1134983061437],[-80.99220587623299,35.158420777504745],[-83.65089728248286,34.671948926428996],[-83.85963751685802,33.891272054223364],[-83.84865118873311,32.010746736868654],[-83.31032111060784,31.309406168163207],[-82.45338751685738,30.6311690732732],[-80.15724493873236,30.385070283872437],[-79.03663946998299,30.49873173190622],[-77.44362189185789,31.674764007288985],[-76.56471564185757,33.029728245050364],[-76.64161993873286,33.69040245253204],[-77.00416876685775,34.60867695038871]]],"type":"Polygon"}}
then performs a geospatial query using MongoDB:
  const results = await collection.find({
    geometry: {
      '$geoIntersects' : {
        '$geometry': {
          type: storm.geometry.type,
          coordinates: storm.geometry.coordinates
        }
      }
    }
  }).toArray()
This translates to "find documents whose 'geometry' field intersects the geometry of the storm".
The script outputs four results:
[ 'south carolina', 'north carolina', 'georgia', 'florida' ]
				通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。



评论