我一直喜欢向您展示一些实际示例的教程。他们有助于了解如何使用代码在生产环境中实际构建应用程序。然后,我可以利用这些知识来建立自己的知识。在本教程中,我们将把世界地理位置 数据存储在Mongo集合中。
在存储环境中,这可能意味着处理大量数据。这就是数据库的主要用途。它们为您提供了一个界面,可以直接从Node.js程序创建,读取,编辑(更新)和删除 大量数据(例如用户数据,帖子,评论,地理位置坐标等)。
“完整”不是指每个Mongo函数的文档。而是在构建PWA时将Mongo代码的实例用作实际示例。
Mongo 集合类似于MySQL数据库中的表。除了在Mongo中,所有内容都存储在类似JSON的对象中(但也使用BSON来存储唯一的_id属性,类似于MySQL存储唯一行键的方式。)
在Mac 上的Terminal或Windows 10上的bash.exe中,使用ssh root@xx.xxx.xxx.xx登录到远程主机(将x替换为Web主机IP地址。)然后使用cd导航至例如,远程主机(/ dev / app)上的项目目录。
安装系统范围的Mongo服务:
须藤apt-get install -y mongodb
该-y指令将自动回答“是”将所有的安装问题。
之后,我们需要启动mongo服务(在下一节中说明)。
就像MySQL具有命令行外壳程序一样,我们可以在其中创建表,用户等。Mongo也具有自己的外壳程序来创建集合,显示数据库等。
首先,我们需要启动 Mongo服务:
sudo服务mongodb启动
如果您需要停止 mongo服务器,可以执行以下操作:
sudo服务mongodb停止
(但不要这样做,我们需要在下一部分中运行该服务!)
要输入Mongo shell,请在cli / bash中输入mongo命令:
蒙哥
您将看到bash变为> character。让我们键入use命令来创建一个新的数据库(或切换到现有数据库):
>使用用户切换到数据库用户
输入> db以确认我们确实切换到了用户数据库:
>分贝使用者
让我们通过执行show dbs命令来查看所有现有数据库:
>显示数据库管理员0.000GB本地0.000GB
即使我们在较早的步骤中创建了用户数据库,该数据库也不在此列表中。为什么?那是因为我们还没有向数据库添加任何集合。这意味着用户实际上已经存在,但是直到添加集合后它才会显示在此列表中。
让我们向用户数据库添加一个新集合。请记住,mongo中的集合等效于MySQL 中的表:
db.users.insert({name:“ felix”})
我们只是将一个集合插入到用户数据库中。
让我们运行>现在显示数据库:
>显示数据库管理员0.000GB本地0.000GB用户0.000GB
只需在用户数据库中插入一个类似JSON的对象即可创建一个“ 表”。但是在Mongo中,它只是基于文档的模型的一部分。您可以在该对象中插入更多对象,并像对待MySQL中的行 / 列一样对待它们。
安装Mongo NPM软件包
npm install mongodb-保存
在介绍Mongo方法之前,让我们决定要在数据库中存储的内容。让我们看一下世界坐标系。它与笛卡尔完全不同。这里的中心点位于尼日利亚拉各斯附近:
HTML5提供出的现成的地理位置,给我们纬度和经度,只要客户同意共享这些信息。以下代码将在台式机和移动设备上创建一个弹出消息框,要求用户“允许”共享位置。如果用户同意,它将存储在lat和lon变量中:
如果(navigator.geolocation){ navigator.geolocation.getCurrentPosition(function(position){ let lat = position .coords.latitude; let lon = position .coords.longitude; }}
好吧,这是一个很好的开始。
但这还不够。我们需要将其转换为HTML5 <canvas>理解的2D坐标系。我们需要在地图图像上方绘制位置标记!所以我写了这个简单的World2Image函数来解决这个问题:
函数 World2Image(pointLat,pointLon){ const mapWidth = 920;const mapHeight = 468;const x =((mapWidth / 360.0)*(180 + pointLon)));const y =((mapHeight / 180.0)*(90-pointLat));返回 [x,y];}
我们只需将地图图像尺寸分别除以360和180,然后再乘以180 + pointLong和90-pointLat即可调整到中心。将纬度/经度转换为2D坐标的最终代码如下所示:
如果(navigator.geolocation){ navigator.geolocation.getCurrentPosition(function(position){ let lat = position .coords.latitude; let lon = position .coords.longitude; let xy = World2Image(lat,lon); let x = xy [0]; let y = xy [1]; }}
当然,您可以在应用中使用所需的任何数据。我们只需要一个有意义的场景即可为一个潜在的实时日落摄影应用程序演示实际示例。
将代码放在PWA中<head>标记内的<script>标记之间。最好在里面:window.onload = event => { / *在这里* / };
现在,每次有新访客加入我们的页面时,都会要求他们共享地理位置。一旦他们按下“允许”按钮,它将被收集并存储在lat,lon,x和y vars中。然后,我们可以创建Fetch API调用,以将其发送到后端服务器。
API端点往返
以下是部分:前端,后端和前端。开发API端点(例如/ api / user / get)时,您通常会遵循这种模式。首先,我们需要调用Fetch API来触发到端点的HTTP请求。
这是给我们两个Fetch API请求的简单代码。目前,我们只需执行这两个操作即可构建我们的地理位置API。在本文的稍后部分,我将向您展示它们如何在后端连接到Mongo。
类用户{ constructor(){ / *当前未使用* / 此 .array = []; } } //使JSON有效负载 let make = function(payload){ return {method:'post', 标头:{'Accept':'application / json', 'Content-Type':'application / json'}, 正文:JSON.stringify(payload)}; } / * / api / add / user 将用户的地理位置发送到mongo 有效载荷= {x:0,y:0,纬度:0.0,lon:0.0} * / User.add = 函数(有效载荷){ fetch(“ / api / add / user”,make(有效载荷)) .then(promise => promise.json())。then(json => { 如果(json.success) console.log(`已输入位置数据。); 其他 console.warn(`位置无法输入!`); }); } / * / api / get / users 获取共享它的所有用户的地理位置* / User.get = function(payload){ fetch(“ / api / get / users,make(payload)) .then(承诺=> promise.json()) .then(json => { 如果(json.success) console.log(`位置数据已成功获取。); 其他 console.warn(`无法获取用户!); }); }
现在,我们可以使用静态用户函数来进行Fetch API调用。当然,没有什么阻止您简单地在代码中任何有意义的地方调用fetch函数。只是将所有内容放入User对象可帮助我们组织代码。
本教程假定您正在运行Node and Express。显示如何进行设置将需要另外一个完整的教程。但是,这是Express中编码的核心API命令。这很简单。
下面的代码来自express.js文件-完整的SSL服务器。如果计划在远程主机上实施此更改,则唯一需要更改的就是使用certbot和LetsEncrypt生成自己的SSL证书。
首先,我们需要初始化所有内容:
/ *包括普通服务器软件包... * / const express = require('express');const https = require('https');const fs = require('fs');const path = require('path');/ * multer是用于上传图片的模块* / const multer = require('multer');/ * sharp与multer一起调整图像大小* / const sharp = require('sharp');/ *实例化express应用... * / const app = express();const端口= 443;//创建Mongo客户端const MongoClient = require('mongodb')。MongoClient;// Multer中间件设置const storage = multer.diskStorage({ 目的地:功能(要求,文件,cb){cb(null,'。/ sunsets')}, 文件名:函数(要求,文件,cb){cb(null,file.fieldname +'-'+ Date.now())}});// Multer将自动创建文件夹上传(” ./sunsets')const的上传= multer({存储:存储});// body-parser是快速安装中随附的中间件。发送POST正文需要以下3行;如果不包括它们,则POST正文将为空。const bodyParser = require('body-parser');app.use(bodyParser.urlencoded({extended:true}));app.use(bodyParser.json());//创建一些静态目录。您网站上的静态文件夹实际上并不存在。它只是另一个文件夹的别名。但是您也可以将其映射为相同的名称。在这里,我们只是向前端公开一些文件夹。app.use('/ static',express.static('images'));app.use('/ sunsets',express.static('sunsets'));app.use('/ api',express.static('api'));app.use('/ static',express.static('css'));app.get('/',function(req,res){res.sendFile(path.join(__ dirname +'/index.html'));});//通用的响应函数-将json对象发送回浏览器以响应请求函数 response(response,content){ const jsontype =“ {'Content-Type':'application / json'}”; response.writeHead(200,jsontype); response.end(content,'utf-8');}//实用程序函数...将缓冲区转换为JSON对象函数 json(chunks){ return JSON.parse(Buffer.concat(chunks).toString())}
我们仍然需要将端点添加到express.js文件。假定下面的代码位于我们上面编写的文件下面的同一文件中。
使用Express创建POST API端点很容易。当我们使用前面提到的从客户端(使用User对象及其静态方法)进行的访存调用时,以下代码将在服务器上触发。
该服务器端端点会将地理位置数据添加到Mongo数据库。
//端点:api / add / user// POST方法路线-将地理位置添加到Mongo的摄影师集合 app.post('/ api / add / user',函数(req,res,next){ const ip = req.connection.remoteAddress; const {x,y,lat ,lon} = req.body; //连接到mongo,如果尚不存在此用户,则插入该用户 MongoClient .connect(`mongodb:// localhost /`,function(err,db){ const Photographer = db.collection('Photographer'); //检查此用户是否已经存在于 摄影师组 .count({ip:ip})。then(count => { 如果(count == 1){ console.log(`$ {ip}的用户已经在mongo中了。); db.close(); } 其他 { console.log(`$ {ip}的用户在mongo中不存在...插入...`); 让用户= {ip:ip,x:x,y:y,lat:lat,lon:lon}; //插入地理位置数据! Photographer.insertOne(用户,(错误,结果)=> { 如果(错误) 扔埃罗; // console.log(“ insertedCount =”,result.insertedCount); // console.log(“ ops =”,result.ops); db.close(); }); } }); res.end('ok'); });});
该服务器端端点将以JSON格式获取Mongo数据库中所有当前存储的地理位置的列表。
//端点:api / get / users// POST方法路线-从Mongo的摄影师集合 app.post('/ api / get / users',函数(req,res,next)中获取所有地理位置 { //连接到Mongo服务器 MongoClient .connect(`mongodb:// localhost /`,函数(err,db){ const Photographer = db.collection('Photographer'); Photographer.find({},{},function(err,cursor){ //注意:您必须将limit()应用于光标 //,然后从数据库中检索任何文档。 cursor.limit(1000); 让用户= []; // console.log(cursor); cursor.each(function(error,result){ if(error)throw error; if(result){ // console.log(result); 让用户= {x:result.x,y:result.y,lat: result.lat,lon:result.lon}; // console.log(“ user [” + users.length +“] =”,用户); users.push(用户); } }); //更合适的实现:(WIP) (异步函数(){ const cursor = db.collection(“ Photographer”)。find({}); while(await cursor.hasNext()){ const doc = 等待光标。 next(); //在此处处理文档 } })(); setTimeout(time => { const json =`{“ success”:true,“ count”:$ {users.length},“ userList”:$ {JSON.stringify(users}}}``; 响应(res,json) ; },2000); }); });});
这将通过Node multer包从HTML表单上传图像。
//端点:api / sunset / upload// POST方法路由-使用multer app.post('/ api / sunset / upload',upload.single('file'),function(req,res,next)从表单中上传图片 { if(req.file) { // console.log(“ req.file.mimetype”,req.file.mimetype); // const {filename:image} = req.file.filename; 让 ext = req.file.mimetype.split('/')[1];让 Stamp = new Date()。getTime();// console.log(“ ext =”,ext); 输出=`./sunsets/sunset-$ {stamp}。$ {ext}`; output2 =`https://www.infinitesunset.app/sunsets/sunset-$ {stamp}。$ {ext}`; console.log(“ output =”,output); // console.log(“ output2 =”,output2); 锋利的(req.file.path) .resize(200).toFile(output,(err,info)=> { // console.log(err); // console.log(info.format); }); // fs.unlinkSync(req.file.path); res.end(`<html> <body style ='font-size:50px'> <img src =“ $ {output2}” style =“ width:100%;”> <div style =“ text-align:center ; margin-top:50px;“>已上传图片!<a href ='https://www.infinitesunset.app' target ='sunset'>返回</a> </ div> </ body> </ html >`,`utf-8`); } // req.file是`avatar`文件 // req.body将保存文本字段(如果有的话) res.end(`<html> <body>出问题了。</ body> </ html>`,`utf-8`);});
首先,我们将使用.insertOne和.find Mongo收集方法。插入位置条目时,我们将测试该条目是否已存在于数据库中。如果是这样,则无事可做。如果没有,我们将插入一个新条目。
您还可以使用Mongo的.count方法对与特定文档过滤器匹配的文档中的条目数进行计数。
要执行任何Mongo操作,我们首先需要从Node应用程序内部连接到Mongo服务器!这是使用.connect方法完成的。
MongoClient .connect(mongodb:// localhost /,函数(err,db){ / * mongo code * / };
完成后,我们需要关闭数据库连接:
MongoClient .connect(mongodb:// localhost /,函数(err,db){ db.close();};
Photographer.insertOne(user,(erro,result)=> { if(error) throw error; // console.log(“ insertedCount =”,result.insertedCount); // console.log(“ ops =”,result.ops); 别忘了关闭数据库 db.close();});
在这里,results.ops将显示插入的对象。
find方法在Mongo中产生称为游标的东西。该光标是一个对象,您可以调用.each来遍历所有找到的项目。根据Mongo文档,您应该始终首先使用cursor.limit(1000);设置一个限制。
Photographer.find({},{},function(err,cursor){ //注意:您必须将limit()应用于光标 //,然后从数据库中检索任何文档。 cursor.limit(1000); 让用户= []; // console.log(cursor)是[Cursor object]; cursor.each(函数(错误,结果){ //检查错误 ,如果(错误) 抛出的错误; //获取数据 let x = result.x;令 y = result.y; / *等... * / }}
现在,我们已经在后端运行了基本的Mongo API,我们可以将数据发送回前端,并且客户端需要在屏幕上直观地显示数据。
我选择使用HTML5 <canvas>将坐标绘制为图像。要在画布上绘制图像,首先必须将它们作为带有IMG标签的常规图像包含在HTML文档中。要准备图像,让我们包括将其缓存在浏览器中:
<style type =“ text / css”> / *加载图像但将其移出屏幕* /#you,#world,#mark {位置:绝对;顶部:-1000px;左:-1000px} </ style><img src =“ you.png” id =“ you” /> <-您的位置-> <img src =“ world.png” id =“ world” /> <-世界地图图像-> < img src =“ marker.png” id =“ marker” /> <-通用位置标记->
现在是我们前端的核心。此调用将执行很多操作:查看设备浏览器是否支持HTML5地理位置属性,创建2D画布并在其上绘制世界地图图像,获取HTML5地理位置数据,使用Fetch API将其发送到Mongo,再进行一次调用以获取之前的所有信息通过基于返回的JSON对象绘制标记,将项目插入后端的mongo数据库中并为画布设置动画:
<script type =“ module”> //创建有效负载-到处都是冗余的 //因为所有POST负载都是JSON //现在在整洁的make()函数中 let make = function(payload){ return {method:'post', 标头:{'Accept':'application / json'}, 正文:JSON.stringify(payload)}; }); //安全的入口点,已加载所有图像,等等 。window.onload = 函数(事件){ //一个存储位置标记的地方 window.markers = []; //因为这是<script type =“ module”,所以要创建User对象 //全局可用,因此可以在HTML属性事件中使用, //我们必须手动将其添加到window对象 window.onload = U => { window.User =用户; } //创建2D canvas const c = document.getElementById(“ canvas”);const ctx = c.getContext(“ 2d”); //获取图像 const world = document.getElementById(“ world”);const here = document.getElementById(“ here”);const marker = document.getElementById(“ marker”); 如果(navigator.geolocation){ navigator.geolocation.getCurrentPosition(函数(位置){ 让 lat = position.coords.latitude;令 lon = position.coords.longitude;令 xy = World2Image(lat,lon);令 x = xy [0];令 y = xy [1]; console.log(`您处于$ {lat} x $ {lon}或= $ {x} x $ {y}`); //将此用户添加到mongo User.add({x:x,y:y,lat:lat,lon:lon}); //获取我们的用户位置 fetch(“ / api / get / users”,make({}))。then( promise => promise.json())。then(json => { / *存储返回的标记列表* / window.markers = json.userList; //选择性地调试每个条目: json.userList.forEach(摄影师=> { // console.log(photographer); }); //删除加载栏 window [“ loading”]。style.display ='none'; //显示返回的项目数 console.log(“ json.userList.length”,json.userList.length); }); //实时绘制所有位置的动画循环 function loop(){ if(here && ctx){ //绘制世界地图 ctx.drawImage(world,0,0,920,468); ctx.save(); //移动到画布的中心 ctx.translate(x,y); //绘制图像 ctx.drawImage(此处-here.width / 2,-here.width / 2); //绘制标记图像 ctx.translate(-x,-y); 如果(window.cameras){ window.cameras.forEach(cam => ctx.drawImage(宝丽来, cam.x-polaroid.width / 2, cam.y-polaroid.width / 2)); } ctx.restore(); //恢复上下文 } requestAnimationFrame(loop); } requestAnimationFrame(loop); }); } else msg.innerHTML =“此浏览器不支持地理位置。 }</ script>
注意...您不必以这种确切方式呈现数据。如果您使用的是React库,请继续使用组件。没关系 在这里,我仅将Vanilla JavaScript用于此示例。重要的是获取请求以及我们正在屏幕上呈现包含位置数据的返回的JSON对象。您不必使用画布。您可能只为每个标记使用了DIV元素。
在i nfinitesunset.app实时摄影应用程序中打开本教程的演示。
检查此Express.js SSL MongoDB服务器的完整源代码。对于那些试图让Mongo在远程主机上工作的人来说,这是一个很好的起点。⭐加星标,Star 叉,
2023-03-22 10:04:19