mongodb atlas_具有MongoDB Atlas,Microsoft Azure和无服务器功能的自定义WordPress仪表盘!...

mongodb atlas

TL;DR I’m building a custom WordPress dashboard for an enterprise client which is powered by React.js on top of Node.js with MongoDB Atlas as the database.

TL; DR我正在为企业客户端构建一个自定义WordPress仪表板,该数据库由MongoDB Atlas作为数据库,由Node.js之上的React.js提供支持。

This dashboard uses several Microsoft Azure services, e.g., Cognitive Services, Azure App Services, and especially serverless ⚡ Azure Functions. In this post, you’ll learn how to build a small module from it and the reason behind my choice of stack, apps, and products.

该仪表板使用了多个Microsoft Azure服务,例如认知服务,Azure应用程序服务,尤其是无服务器的Azure Azure功能。 在本文中,您将学习如何从中构建一个小模块,以及选择堆栈,应用程序和产品背后的原因。

? One of my enterprise clients who owns a huge networking and media company has a large-scale WordPress site set up. He recently consulted me about the possibility of building a custom WordPress dashboard (based on the WordPress REST API) — to help him make intelligent business decisions via Machine Learning and Artificial Intelligence.

? 我的一家拥有大型网络和媒体公司的企业客户中,有一个大规模的WordPress网站已建立。 最近,他向我咨询了有关构建自定义WordPress仪表板(基于WordPress REST API )的可能性-帮助他通过机器学习和人工智能做出明智的业务决策。

? With JavaScript eating up the world and WordPress adapting to the move by creating the Gutenberg project — I thought of an architecture/stack where WordPress would be our content layer, a familiar battle-tested environment that does its job well with a custom dashboard that’s built with JavaScript.

? 随着JavaScript吞噬了整个世界并且WordPress通过创建Gutenberg项目适应了这一变化–我想到了一个架构/堆栈,其中WordPress将成为我们的内容层,这是一个经过实践检验的熟悉环境,可以通过内置的自定义仪表板很好地完成工作使用JavaScript。

? When you’re tasked to build a modern JavaScript application, you find yourself in a mix of different frameworks, tools, and dev-workflows. The JavaScript eco-system has grown a lot over the last couple of years. We have many many good options available today.

? 当您负责构建现代JavaScript应用程序时,您会发现自己陷入了各种不同的框架,工具和开发工作流程的混合之中。 在过去的几年中,JavaScript生态系统有了很大的发展。 今天我们有很多不错的选择。

? So, after researching my options for a bit — I opted to use React.js on top of Node.js to start building the custom WordPress dashboard. While the project is in its ideation phase at the moment, I think it’s important that I share some of our goals here to define context behind my choice of the stack.

? 因此,在仔细研究了我的选项之后,我选择在Node.js之上使用React.js来开始构建自定义WordPress仪表板。 尽管该项目目前处于构思阶段,但我认为在此分享一些我们的目标以在我选择堆栈的背后定义上下文非常重要。

自定义WordPress仪表板目标 ( Custom WordPress Dashboard Goals )

Imagine you own a large networking company where over 500 hotels (in three different countries) use your services to power their conference halls, IT meetings, and online property management like the sites and blogs. That’s what my client does.

想象一下,您拥有一家大型网络公司,在这三个不同国家/地区的500多家酒店中,有500多家酒店使用您的服务来为其会议厅,IT会议以及网站和博客等在线财产管理提供动力。 那是我的客户所做的。

Most of this is powered by a huge multi-site WordPress instance that manages everything for the hotels, websites, online booking, registrations, events, tickets, reviews, and comments. There’re also other systems running different software which are able to produce content via REST API.

其中大部分功能都由一个大型的多站点WordPress实例提供支持,该实例管理酒店,网站,在线预订,注册,事件,门票,评论和评论的所有内容。 还有其他运行不同软件的系统,它们可以通过REST API生成内容。

We’ve set out to create a custom WordPress dashboard with many goals in mind but I’m listing a few of them which are related to this particular article. Take a look at what I have built so far, it’s all based on serverless Azure functions — which are pretty awesome.

我们已经着手创建一个自定义WordPress仪表板,并牢记了许多目标,但我列出了其中一些与本文相关的目标。 看一看到目前为止我构建的内容,它们都是基于无服务器Azure功能-相当出色。

? 高级数据报告 (? High-level Data Reporting)

The custom dashboard will report all the high-level data, e.g. things like live sales happening throughout my client’s portfolio (500+ hotels), entity/time based and date based breakdowns.

定制仪表板将报告所有高级数据,例如,在我的客户投资组合(500多家酒店)中发生的实时销售,基于实体/时间和基于日期的明细数据。

And that how each of his franchise performing on a daily, weekly, monthly basis. All of this data is being fed to MongoDB Atlas. More on that later.

以及他的每个专营权每天,每周,每月的表现。 所有这些数据都被馈送到MongoDB Atlas 。 以后再说。

⚡无服务器自动化 (⚡Serverless Automation)

Most of the modules are to built upon serverless architecture — which in this case provides huge benefits. All the automation is always running and the cost is paid as you go i.e. pay for what you use.

大多数模块都建立在无服务器架构上,在这种情况下,它提供了巨大的好处。 所有的自动化系统始终处于运行状态,并且成本随您所用即付,即按需使用。

An initial rough estimate puts this solution 34% more economical than having a server VM running all the time. We are using Azure Functions for this serverless automation.

初步估算,此解决方案比始终运行服务器VM的经济性高34%。 我们正在使用Azure Functions进行这种无服务器自动化。

? 物联网中心 (? IoT (Internet of Things) Hub)

There are about ~200 IT managers working for my client who have IoT enabled devices that feed data into several online projects. This custom dashboard also includes that data for making better decisions and connecting the whole registration, management, maintenance team’s hub into a single place.

大约有200位IT经理为我的客户工作,他们拥有支持IoT的设备,这些设备可以将数据馈送到几个在线项目中。 该自定义仪表板还包含用于做出更好决策的数据,并将整个注册,管理和维护团队的中心连接到一个位置。

As you might have already guessed, this project makes use of IoT Hub from Microsoft Azure to connect, monitor, and manage all of the IoT assets.

您可能已经猜到了,该项目利用Microsoft Azure的IoT中心来连接,监视和管理所有IoT资产。

? 机器学习与人工智能 (? Machine Learning and Artificial Intelligence)

We’re using a lot of different services from Microsoft Azure for the sake of making this dashboard artificially intelligent by Machine Learning.

我们正在使用Microsoft Azure提供的许多不同服务,以使Machine Learning能够使该仪表板人为地智能化。

There’s a huge dataset that is fed to the ML Studio which later helps us predict different decisions like space management, low registrations trends for IT events, and questions like why and when these things happen.

有一个巨大的数据集被馈送到ML Studio ,这以后可以帮助我们预测不同的决策,例如空间管理,IT事件的低注册趋势以及诸如此类问题的发生时间和时间等问题。

While the Machine learning part is beyond the scope of this article, I still plan to touch the base with some of the awesome Artificial intelligence I’ve been able to cook in via Azure’s Cognitive Services.

尽管机器学习部分不在本文讨论范围之内,但我仍然计划使用一些我已经能够通过Azure的Cognitive Services制作的出色人工智能来打基础。

? 实时直播 (? Live & Real Time)

One of the most important aspects of this custom dashboard is that it’s live and real time. Which means, I need a managed database that can cope with this amount of data and still stay highly available.

此自定义仪表板最重要的方面之一是实时和实时。 这意味着,我需要一个托管数据库,该数据库可以应付如此大量的数据,并且仍然保持高可用性。

But at the same time, it’s for the management purposes and doesn’t need to have any impact on the WordPress sites. That is a crucial system design decision for this dashboard.

但同时,这只是出于管理目的,不需要对WordPress网站产生任何影响。 这是该仪表板的关键系统设计决策。

By that what I mean is we can do all sorts of experiments with this custom dashboard but it shouldn’t have any impact on the database/servers which are running the multi-site WordPress instance.

我的意思是,我们可以使用此自定义仪表板进行各种实验,但对运行多站点WordPress实例的数据库/服务器不应该有任何影响。

MongoDB和MongoDB Atlas ( MongoDB & MongoDB Atlas )

For this custom WordPress dashboard, I am using MongoDB Atlas as a DBaaS (Database as a Service). And I couldn’t be happier. When I first shared that I’ll be using MongoDB, many developers had concerns.

mongodb atlas_具有MongoDB Atlas,Microsoft Azure和无服务器功能的自定义WordPress仪表盘!..._第1张图片
Most of the questions were about why add another layer of complexity by adding yet another database to the mix. Why not use the WordPress database as it is. To answer these questions and more I have prepared a list of reasons to why I am using MongoDB Atlas.

对于此自定义WordPress仪表板,我将MongoDB Atlas用作DBaaS(数据库即服务)。 而且我再也不能快乐了。 当我第一次分享我将使用MongoDB时,许多开发人员都对此感到担忧。 大多数问题是关于为什么要通过添加另一个数据库来增加另一层复杂性。 为什么不按原样使用WordPress数据库。 为了回答这些问题,我准备了使用MongoDB Atlas的原因的清单。

♨不喜欢RDBMS (♨ Dislike for RDBMS)

I personally dislike relational databases. Most of the times, for me they get in the way of building applications. I have to completely get out of the app I am building, think about my database in future and design a good schema which always ends up in a bad exercise for my dev-workflow. It’s counter-intuitive at best — at least for me, it is.

我个人不喜欢关系数据库。 在大多数情况下,对我来说,它们妨碍了构建应用程序。 我必须完全退出正在构建的应用程序,在以后考虑我的数据库并设计一个好的架构,该架构总是对我的开发工作流造成不良影响。 充其量是违反直觉的,至少对我而言是这样。

? 硬盘便宜 CPU / RAM不是 (? HDD Is Cheap | CPU/RAM Is Not)

Old databases were mostly designed in a way to save disk space among other things. This led to a plethora of problems like normalization, indexing, and made sharding, auto-scaling, and replication harder.

旧数据库的设计主要是为了节省磁盘空间。 这导致了许多问题,例如规范化,索引编制,并使分片,自动缩放和复制变得更加困难。

Nowadays, disk space is dirt-cheap. On the other hand, CPU/RAM is not and your sys-admin cost can skyrocket very quickly if you end up with a bad choice here.

如今,磁盘空间非常便宜。 另一方面,CPU / RAM不是,如果您在这里最终选择错误,则系统管理员的成本可能会Swift飙升。

Like you wanted to create a custom dashboard but your system design architect cost you two sys-admins with how he chose to design your system. Similarly, my client wanted a managed solution without having to hire a team of IT/DevOps folks — at least for an experimental custom dashboard.

就像您想创建一个自定义的仪表板一样,但是您的系统设计架构师却花了两个系统管理员来决定他如何选择设计系统。 同样,我的客户想要一种托管解决方案,而不必雇用IT / DevOps团队(至少用于实验性自定义仪表板)。

? MongoDB专业版 (? MongoDB’s Pro)

  • Schema-less. Flexible schema for-the-win. I don’t have to change anything, my regular app-dev workflow, creating a Node.js based app where I am manipulating with JSON type data, I can just feed that into MongoDB and it just works.

    无模式 。 灵活的双赢方案。 我不需要更改任何东西,我的常规app-dev工作流程,创建了一个基于Node.js的应用程序,可以在其中处理JSON类型数据,我可以将其输入到MongoDB中并且可以正常工作。
  • Workflow-consistency. Creates documents the way my custom dashboard is represented. Sales, Videos, Talks, Comments, Reviews, Registrations, etc. all of that have similar data representation on the frontend and the backend — and even in the database. I manage 3rd party data via middleware. This consistency translates to clean code.

    工作流一致性 。 以表示我的自定义仪表板的方式创建文档。 销售,视频,演讲,评论,评论,注册等在前端和后端(甚至在数据库中)都具有相似的数据表示。 我通过中间件管理第三者数据。 这种一致性转化为干净的代码。
  • Ease of scale-out. It scales reads by using replica sets. Scales writes by using sharding (auto balancing). Just fire up another machine and away you go. Most importantly, instead of vertical scaling via RDBMS, MongoDB lets you scale horizontally with different levels of consistency. That’s a big plus. ➕

    易于横向扩展 。 它通过使用副本集扩展读取。 通过使用分片(自动平衡)扩展写入。 只需启动另一台机器,然后您就可以离开。 最重要的是,除了通过RDBMS进行垂直扩展外,MongoDB还允许您以不同的一致性级别进行水平扩展。 这是一大优势。 ➕
  • Cost. Depends on which RDBMS of course, but MongoDB is free and can run on Linux, ideal for running on cheaper commodity kit.

    费用 。 当然取决于哪个RDBMS,但是MongoDB是免费的,可以在Linux上运行,非常适合在便宜的商品套件上运行。

? 为什么选择MongoDB Atlas ? (? Why MongoDB Atlas?)

Well, now that I know MongoDB is the right database choice, there are so many different options to host your database. I can self-host on my Linux machine via DigitalOcean, use a cloud provider like AWS/Azure or a choose a DBaaS service specific to MongoDB.

好了,既然我知道MongoDB是正确的数据库选择,那么有许多不同的选项可以托管您的数据库。 我可以通过DigitalOcean在Linux机器上自托管,使用AWS / Azure之类的云提供商或选择MongoDB专用的DBaaS服务。

mongodb atlas_具有MongoDB Atlas,Microsoft Azure和无服务器功能的自定义WordPress仪表盘!..._第2张图片

But I want a fast, secure, and managed MongoDB solution that I can easily scale with the growth of the number of modules we attach in this custom WordPress dashboard. That’s MongoDB Atlas.

但是我想要一个快速,安全和托管的MongoDB解决方案,我可以随我们在此自定义WordPress仪表板中附加的模块数量的增加轻松地进行扩展。 那就是MongoDB Atlas 。

MongoDB Atlas is a cloud-hosted MongoDB service engineered and run by the same team that builds the database. And guess what, I trust that they follow the best operational practices since they are the ones who’re building MongoDB in the first place.

MongoDB Atlas是由云托管的MongoDB服务,由构建数据库的同一团队设计和运行。 猜猜是什么,我相信他们遵循最佳的操作实践,因为他们是首先构建MongoDB的人。

I want this custom dashboard to be self-managed, serverless, and using MongoDB Atlas saves me from worrying about software patching, backups, and reliable configuration setup for new DB updates. Again a big plus. ➕

我希望该自定义仪表板能够自我管理,无服务器,并且使用MongoDB Atlas可以使我不必担心软件补丁,备份和新数据库更新的可靠配置设置。 再一次大加。 ➕

Also, the fact that MongoDB Atlas is supported cross-platform as well as cross region and across different cloud providers makes it a much better choice. I think each Cluster comes with two replica sets, ready to scale.

而且,MongoDB Atlas在跨平台,跨区域以及跨不同的云提供商的支持下,这一事实使其成为更好的选择。 我认为每个集群都有两个副本集,可以扩展。

? MongoDB指南针 (? MongoDB Compass)

Now that we are going to work with MongoDB, it’d be great to have a tool through which we can explore our database, view the changes, debug and what not. For this purpose, MongoDB again takes the lead with a product called MongoDB Compass. Take a look.

现在我们将与MongoDB一起工作,拥有一个可以用来浏览数据库,查看更改,调试以及不进行调试的工具将是很棒的。 为此,MongoDB再次以称为MongoDB Compass的产品领先。 看一看。

mongodb atlas_具有MongoDB Atlas,Microsoft Azure和无服务器功能的自定义WordPress仪表盘!..._第3张图片

I suggest that you go ahead and download MongoDB Compass. It’s literally the best tool to visualize your MongoDB database. Here’s a set of features:

我建议您继续下载MongoDB Compass 。 实际上,它是可视化MongoDB数据库的最佳工具。 这是一组功能:

  • Visualize and explore: Take a look at your database, find out how things are looking, and even visualize stuff like maps/coordinates.

    可视化和探索:查看数据库,了解事物的外观,甚至可视化诸如地图/坐标的内容。
  • Insert, modify, and delete: You can also perform CRUD operations for your DB right from MongoDB compass. Makes testing easier.

    插入,修改和删除:您还可以直接从MongoDB指南针对数据库执行CRUD操作。 使测试更加容易。
  • Debug and optimize: Finally, analyze your data, debug it and even find out about performance issues right inside a great GUI for your database. This tool is a must-have if you work with MongoDB.

    调试和优化:最后,对数据进行分析,调试,甚至在数据库的出色GUI内查找性能问题。 如果您使用MongoDB,则此工具是必备工具。
  • Extensible: And the best part is you can build your own plugins to extend MongoDB Compass. Here’s the documentation on building your own Compass plugins.

    可扩展:最好的部分是您可以构建自己的插件来扩展MongoDB Compass。 这是有关构建自己的Compass插件的文档。
  • Enterprise Flavor: MongoDB Compass comes in a few flavors: Community (Free), and Enterprise (Licensed) — the Enterprise version is the one that lets you visualize DB schema.

    企业风格:MongoDB Compass有以下几种风格:社区(免费)和企业(许可)-企业版是使您可视化数据库架构的版本。

Mon MongoDB Atlas入门 ( ✅ Getting Started with MongoDB Atlas )

Let’s get started and build a simple module which’s part of the custom WordPress dashboard that I am building. For this module, we are collecting all the sales related data. For that, we need a MongoDB instance, and we’re of course using MongoDB Atlas here.

让我们开始构建一个简单的模块,该模块是我正在构建的自定义WordPress仪表板的一部分。 对于此模块,我们正在收集所有与销售有关的数据。 为此,我们需要一个MongoDB实例,我们当然在这里使用MongoDB Atlas。

步骤#1:转到MongoDB地图集→ (Step #1: Go to MongoDB Atlas →)

Go to the MongoDB Atlas site and register a completely free MongoDB instance hosted on AWS, with shared RAM and 512 Mb storage. Click the Get Started Free button.

转到MongoDB Atlas网站并注册一个完全免费的MongoDB实例,该实例托管在AWS上,具有共享RAM和512 Mb存储。 单击Get Started Free按钮。

mongodb atlas_具有MongoDB Atlas,Microsoft Azure和无服务器功能的自定义WordPress仪表盘!..._第4张图片

步骤#2:在MongoDB Atlas上注册→ (Step #2: Sign up at MongoDB Atlas →)

Now go ahead and sign up with your email ID and fill up the details. It’s amazing that you can sign up and use a free MongoDB Atlas hosted DB instance and they don’t even require you to add a credit-card for that.

现在,继续并使用您的电子邮件ID签名并填写详细信息。 您可以注册并使用免费的MongoDB Atlas托管数据库实例真是太神奇了,它们甚至不需要您为此添加信用卡。

mongodb atlas_具有MongoDB Atlas,Microsoft Azure和无服务器功能的自定义WordPress仪表盘!..._第5张图片

步骤#3:创建集群 (Step #3: Create the Cluster)

Now you’ll be redirected to a page with a bunch of information about the new MongoDB Cluster you’re about to create. I suggest that you review this information, and move ahead by clicking the Create Cluster button at the bottom just like in the screenshot below.

现在,您将被重定向到一个页面,其中包含有关将要创建的新MongoDB集群的大量信息。 建议您查看此信息,然后单击底部的“ Create Cluster按钮,如下面的屏幕截图所示,继续进行操作。

mongodb atlas_具有MongoDB Atlas,Microsoft Azure和无服务器功能的自定义WordPress仪表盘!..._第6张图片

步骤#4:创建数据库用户/密码 (Step #4: Create DB User/Pass)

It’ll take a minute and your DB will be created. Once that happens, head over to the Security > MongoDB Users and click on the + ADD NEW USER button on the right, to create a new user for your database. Let’s keep all the other settings set to default for the sake of this intro-article.

这将花费一分钟,您的数据库将被创建。 一旦发生这种情况,请转到“ Security >“ MongoDB Users ,然后单击右侧的+ ADD NEW USER按钮,为您的数据库创建一个新用户。 为了介绍本文章,让我们将所有其他设置保持为默认值。

I’m setting the user/pass as usermongo but you know better.

我将用户名/密码设置为usermongo但您知道的更多。

步骤5:将IP添加到白名单以进行访问 (Step #5: Add IP to Whitelist for Access)

To be able to access your MongoDB Atlas database, you need to setup the IP Whitelist with the IP of your server where your app is hosted. Authentication is beyond what I am discussing here so for the purpose of this demo let’s just allow everyone (which’s actually a bad practice in production).

为了能够访问您的MongoDB Atlas数据库,您需要使用托管应用程序的服务器IP设置IP白名单。 身份验证超出了我在此处讨论的范围,因此,出于本演示的目的,我们只允许所有人(这实际上是生产中的不良做法)。

So, again, head over to the Security > IP Whitelist and click on the + ADD IP ADDRESS button on the right, and finally ALLOW ACCESS FROM ANYWHERE button to allow the anonymous access.

所以,再次,头部到Security > IP Whitelist ,然后点击+ ADD IP ADDRESS右边按钮,最后ALLOW ACCESS FROM ANYWHERE按钮允许匿名访问。

步骤#6:通过MongoDB Compass连接 (Step #6: Connect via MongoDB Compass)

Now that our DB’s IP access and a user has been created, we can pick up the connection string and use it to connect to our database with our MongoDB Compass application.

现在已经创建了数据库的IP访问权限和用户,我们可以选择连接字符串,并使用它通过MongoDB Compass应用程序连接到我们的数据库。

Go to Connect then choose Connect with MongoDB Compass and download compass if you haven’t till now, copy the URI Connection String. Finally, open Compass and it should be able to detect the connection string in your clipboard, allow it to connect to your database.

转到“ Connect然后选择“ Connect with MongoDB Compass并下载指南针(如果您还没有下载的话),复制URI连接字符串。 最后,打开Compass,它应该能够检测剪贴板中的连接字符串,并允许其连接到数据库。

And you are set to visualize your database, analyze its performance, and even run complete CRUD operations. Awesome! ?

您将可以可视化数据库,分析其性能,甚至运行完整的CRUD操作。 太棒了! ?

Now that we have created a MongoDB Atlas, connected it with MongoDB Compass, we can move forward and start building our Node.js application.

现在,我们已经创建了MongoDB Atlas,并将其与MongoDB Compass连接起来,我们可以继续并开始构建Node.js应用程序。

Ⓦ =

Ⓦ=

WordPress REST API-FTW! ( WordPress REST API — FTW! )

This WordPress based Node.js custom dashboard interacts with the WordPress instance via WordPress REST API. Since this is a Node.js app, I am using an awesome library called wpapi written by K Adam White. He has also built a demo express based WordPress app. That’s what I got inspired by while building this custom dashboard. SO, you’ll see a lot of it here.

这个基于WordPress的Node.js自定义仪表板通过WordPress REST API与WordPress实例进行交互。 由于这是一个Node.js应用程序,因此我使用的是由K Adam White编写的很棒的库wpapi 。 他还构建了一个基于演示express的WordPress应用程序。 这就是我在构建此自定义仪表盘时得到的启发。 所以,您会在这里看到很多。

? 基于express WordPress自定义路由器 (? WordPress Custom Router Based on express)

The router is set up with express. Here’s a basic error handler and router template for using WordPress with express.

路由器设置有express 。 这是用于将WordPress与express结合使用的基本错误处理程序和路由器模板。

'use strict';

var express = require('express');
var router = express.Router();
var siteInfoMiddleware = require('../middleware/site-info');

// Set global site info on all routes
router.use(siteInfoMiddleware);

// Public Routes
// =============

router.get('/', require('./index'));
router.get('/page/:page', require('./index'));
router.get('/:slug', require('./single'));
router.use('/tags/:tag', require('./tag'));
router.use('/categories/:category', require('./category'));

// Catch 404 and forward to error handler.
router.use(function (req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// Error Handling
// ==============

// Development error handler will print stacktrace.
function developmentErrorRoute(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: err
    });
}

// Production error handler. No stacktraces leaked to user.
function friendlyErrorRoute(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
}

// Configure error-handling behavior
if (router.get('env') === 'development') {
    router.use(developmentErrorRoute);
} else {
    router.use(friendlyErrorRoute);
}

module.exports = router;

? 基本express实施 (? Basic express Based Implementation)

I am not hosting this entire thing on WordPress, but the initial plan was to do just that. If you want to go do that, you’d wanna build the index by querying all the info using the RSVP.hash utility for convenience and parallelism. For that here’s what you should do.

我没有将整个事情托管在WordPress上,但最初的计划是这样做。 如果您想这样做,您可以通过使用RSVP.hash实用程序查询所有信息来建立索引,以方便和并行。 为此,这就是您应该做的。

'use strict';

var wp = require( '../services/wp' );
var contentService = require( '../services/content-service' );
var pageNumbers = require( '../services/page-numbers' );
var pageTitle = require( '../services/page-title' );
var RSVP = require( 'rsvp' );

function getHomepage( req, res, next ) {
  var pages = pageNumbers( req.params.page );

  RSVP.hash({
    archiveBase: '',
    pages: pages,
    title: pageTitle(),
    // Primary page content
    posts: wp.posts().page( pages.current ),
    sidebar: contentService.getSidebarContent()
  }).then(function( context ) {
    if ( req.params.page && ! context.posts.length ) {
      // Invalid pagination: 404
      return next();
    }

    res.render( 'index', context );
  }).catch( next );
}

module.exports = getHomepage;

? 认证熟化 (? Authentication Cooked In)

For this setup, you’ll also need to authenticate your Node.js app by giving it the authentication data, which along with wpapi can be processed like this. Beware this is not always a best practice if you don’t use correct permissions and environment variables settings.

对于此设置,您还需要通过向其提供身份验证数据来对Node.js应用进行身份验证,该数据可以与wpapi一起进行这样的处理。 请注意,如果不使用正确的权限和环境变量设置,这并不总是最佳做法。

var WP = require( 'wordpress-rest-api' );
var _ = require( 'lodash' );

var config = _.pick( require( './config' ).wordpress, [
  // Whitelist valid config keys
  'username',
  'password',
  'endpoint'
]);

var wp = new WP( config );

module.exports = wp;

? 网站内容累积 (? Site Content Accumulation)

And finally, you are able to consume all the content by creating a content-service which handles recursively fetching

最后,您可以通过创建处理递归获取的内容服务来使用所有内容

  • All the pages of a paged collection.

    分页集合的所有页面。
  • Your WordPress site’s info.

    您的WordPress网站信息。
  • An alphabetized list of categories.

    按字母顺序排列的类别列表。
  • A specific category (specified by slug) from the content cache.

    内容缓存中的特定类别(由slug指定)。
  • An alphabetized list of tags.

    标签的字母顺序列表。
  • A specific tag (specified by slug) from the content cache

    内容缓存中的特定标签(由slug指定)
  • Other content required to have some feature parity with WP.

    与WP具有某些功能相等的其他内容。

The code for this looks somewhat like this.

此代码看起来像这样。

'use strict';

var wp = require( './wp' );
var cache = require( './content-cache' );
var _ = require( 'lodash' );
var RSVP = require( 'rsvp' );

/**
 * Recursively fetch all pages of a paged collection
 *
 * @param {Promise} request A promise to a WP API request's response
 * @returns {Array} A promise to an array of all matching records
 */
function all( request ) {
  return request.then(function( response ) {
    if ( ! response._paging || ! response._paging.next ) {
      return response;
    }
    // Request the next page and return both responses as one collection
    return RSVP.all([
      response,
      all( response._paging.next )
    ]).then(function( responses ) {
      return _.flatten( responses );
    });
  });
}

function siteInfo( prop ) {
  var siteInfoPromise = cache.get( 'site-info' );

  if ( ! siteInfoPromise ) {
    // Instantiate, request and cache the promise
    siteInfoPromise = wp.root( '/' ).then(function( info ) {
      return info;
    });
    cache.set( 'site-info', siteInfoPromise );
  }

  // Return the requested property
  return siteInfoPromise.then(function( info ) {
    return prop ? info[ prop ] : info;
  });
}

/**
 * Get an alphabetized list of categories
 *
 * All archive routes display a sorted list of categories in their sidebar.
 * We generate that list here to ensure the sorting logic isn't duplicated
 * across routes.
 *
 * @method sortedCategories
 * @return {Array} An array of category objects
 */
function sortedCategories() {
  return all( wp.categories() ).then(function( categories ) {
    return _.chain( categories )
      .sortBy( 'slug' )
      .value();
  });
}

function sortedCategoriesCached() {
  var categoriesPromise = cache.get( 'sorted-categories' );

  if ( ! categoriesPromise ) {
    categoriesPromise = sortedCategories();
    cache.set( 'sorted-categories', categoriesPromise );
  }

  return categoriesPromise;
}

/**
 * Get a specific category (specified by slug) from the content cache
 *
 * The WP API doesn't currently support filtering taxonomy term collections,
 * so we have to request all categories and filter them down if we want to get
 * an individual term.
 *
 * To make this request more efficient, it uses sortedCategoriesCached.
 *
 * @method categoryCached
 * @param {String} slug The slug of a category
 * @return {Promise} A promise to the category with the provided slug
 */
function categoryCached( slug ) {
  return sortedCategoriesCached().then(function( categories ) {
    return _.findWhere( categories, {
      slug: slug
    });
  });
}

/**
 * Get a specific tag (specified by slug) from the content cache
 *
 * The WP API doesn't currently support filtering taxonomy term collections,
 * so we have to request all tags and filter them down if we want to get an
 * individual term.
 *
 * To make this request more efficient, it uses the cached sortedTags promise.
 *
 * @method tagCached
 * @param {String} slug The slug of a tag
 * @return {Promise} A promise to the tag with the provided slug
 */
function tagCached( slug ) {
  return sortedTagsCached().then(function( tags ) {
    return _.findWhere( tags, {
      slug: slug
    });
  });
}

/**
 * Get an alphabetized list of tags
 *
 * @method sortedTags
 * @return {Array} An array of tag objects
 */
function sortedTags() {
  return all( wp.tags() ).then(function( tags ) {
    return _.chain( tags )
      .sortBy( 'slug' )
      .value();
  });
}

function sortedTagsCached() {
  var tagsPromise = cache.get( 'sorted-tags' );

  if ( ! tagsPromise ) {
    tagsPromise = sortedTags();
    cache.set( 'sorted-tags', tagsPromise );
  }

  return tagsPromise;
}

function getSidebarContent() {
  return RSVP.hash({
    categories: sortedCategoriesCached(),
    tags: sortedTagsCached()
  });
}

module.exports = {
  // Recursively page through a collection to retrieve all matching items
  all: all,
  // Get (and cache) the top-level information about a site, returning the
  // value corresponding to the provided key
  siteInfo: siteInfo,
  sortedCategories: sortedCategories,
  sortedCategoriesCached: sortedCategoriesCached,
  categoryCached: categoryCached,
  tagCached: tagCached,
  sortedTags: sortedTags,
  sortedTagsCached: sortedTagsCached,
  getSidebarContent: getSidebarContent
};

? 自定义路线和销售数据 (? Custom Routes & Sales Data)

Finally, I have cooked in quite a few custom routes from where I can attain any kind of sales related data. For the particular architecture I have in place, I’m again using the RSVP.hash utility for convenience and parallelism. It works like a charm.

最后,我已经按照许多自定义路线进行烹饪,可以从中获取任何与销售相关的数据。 对于已有的特定体系结构,为了方便和并行起见,我再次使用RSVP.hash实用程序 。 它像一种魅力。

var WPAPI = require( 'wpapi' );
var RSVP = require('rsvp');

// Using the RSVP.hash utility for convenience and parallelism
RSVP.hash({
  categories: wp.categories().slug( 'it-services' ),
  tags1: wp.tags().slug('hotel-name'),
  tags2: wp.tags().slug('march-events')
}).then(function( results ) {
    // Combine & map .slug() results into arrays of IDs by taxonomy
    var tagIDs = results.tags1.concat( results.tags2 )
        .map(function( tag ) { return tag.id; });
    var categoryIDs = results.categories
        .map(function( cat ) { return cat.id; });
    return wp.posts()
        .tags( tags )
        .categories( categories );
}).then(function( posts ) {
    // These posts are all fiction, either magical realism or historical:
    console.log( posts );
});

Once I have that data, I am sending it to Paddle.com for processing along with the purchased order request so that it can be added to our MongoDB instance via serverless ⚡ Azure Functions.

有了这些数据后,我会将其与购买的订单请求一起发送到Paddle.com进行处理,以便可以通过无服务器的⚡Azure函数将其添加到我们的MongoDB实例中。

// Registering custom routes.
site.itSales = site.registerRoute( 'sales/v1', '/resource/(?P\\d+)' );
site.itSales().somePart( 7 ); // => myplugin/v1/resource/7

// Query Parameters & Filtering Custom Routes.
site.handler = site.registerRoute( 'sales/v1', 'receipts/(?P)', {
    // Listing any of these parameters will assign the built-in
    // chaining method that handles the parameter:
    params: [ 'before', 'after', 'author', 'parent', 'post' ]
});

// Yields from the custom data of buyers.
site.handler().post( 8 ).author( 92 ).before( dateObj )... // Sent to paddle.

It might look odd to some but WordPress allows you to set up custom post types and custom taxonomies which is what I’m using here, the above code, however, is not the exact implementation but a similar approach to what I have used via categories and tags.

对于某些人来说可能看起来很奇怪,但是WordPress允许您设置自定义帖子类型和自定义分类法,这就是我在这里使用的方法,但是上面的代码并不是确切的实现,而是与我通过类别使用的相似方法和标签。

This data gets sent Paddle, and it’s heavily cached so that our WordPress instances do not get any sort of load while we experiment with the custom dashboard. I’ve also cooked in a small data-refresh module which fetches the data on demand from the WordPress instance of choice.

该数据将发送到Paddle,并且已大量缓存,因此我们在使用自定义信息中心进行实验时,我们的WordPress实例不会受到任何负载。 我还煮过一个小的data-refresh模块,该模块从所选的WordPress实例中按需获取数据。

Microsoft Azure和Azure功能 ( Microsoft Azure & Azure Functions )

While building this custom WordPress dashboard, I wanted to make sure that each module of this dashboard lived in form of a serverless app with multiple serverless functions. This decision was based on keeping this dashboard’s cost as economical as possible.

在构建此自定义WordPress仪表板时,我想确保该仪表板的每个模块都以具有多个无服务器功能的无服务器应用程序的形式存在。 该决定基于使该仪表板的成本尽可能经济。

? 三种选择 (? Three Options)

There are three major cloud services providers present. That are Microsoft Azure, Google Cloud Platform, and Amazon Web Services. Each of which has serverless functions available which are called Azure functions, GCP Cloud Functions, and AWS Lambdas.

目前有三个主要的云服务提供商。 那就是Microsoft Azure , Google Cloud Platform和Amazon Web Services 。 每个功能都有可用的无服务器功能,这些功能称为Azure功能,GCP Cloud功能和AWS Lambda。

? 选择Azure (? Choosing Azure)

Azure has one of the biggest cloud architecture and global presence. 50 Azure regions, more than any cloud provider and after testing each of these three, I found that Azure functions had the best response time in UAE (as my client’s business is based out of UAE).

Azure拥有最大的云架构和全球业务之一。 在50个Azure区域中,比任何一家云提供商都多,并且在对这三个区域中的每一个进行了测试之后,我发现Azure功能在阿联酋具有最佳的响应时间(因为我的客户业务来自阿联酋)。

Also, the fact that we’re using Azure ML Studio, AI Cognitive Services, and Virtual Machines to host parts of this project, it made complete sense to use Azure functions for the serverless architecture.

此外,事实上,我们使用Azure ML Studio,AI认知服务和虚拟机来托管该项目的某些部分,因此将Azure函数用于无服务器体系结构完全有意义。

Azure函数入门 ( Getting Started with Azure Functions )

Let’s get started with Azure functions. I am going to take you through the process of creating a simple serverless Azure function, which will be triggered via HTTP requests, and inside it, we’ll process the sales information sent to us from Paddle.com.

让我们开始使用Azure函数。 我将带领您完成创建简单的无服务器Azure函数的过程,该过程将通过HTTP请求触发,在其中,我们将处理从Paddle.com发送给我们的销售信息。

are我们正在建造什么? (⚙ What are we building?!)

  1. I am building a serverless Azure function which is based on JavaScript and specifically Node.js code.

    我正在构建一个基于JavaScript的无服务器Azure函数,尤其是基于Node.js代码。
  2. This Azure function will get triggered by a simple GET HTTP request from our 3rd party payment solution, i.e., Paddle.com

    来自我们的第三方付款解决方案(即Paddle.com)的简单GET HTTP请求将触发该Azure功能
  3. As soon as there’s a sale on Paddle.com, it will trigger a webhook that contains info related to our sale, quantity, item, earnings, and some member-related data that WordPress sent to Paddle.

    Paddle.com上的交易一旦发生,它将触发一个 Webhook,其中包含与我们的销售,数量,项目,收入以及WordPress发送给Paddle的一些与会员有关的数据有关的信息。
  4. Using WordPress REST API, I have added some custom data related to the user who purchased the product, like user’s ID in WordPress DB, which WordPress site had this sale, and such user’s meta info.

    使用WordPress REST API,我添加了一些与购买该产品的用户有关的自定义数据,例如WordPress DB中的用户ID,该销售的WordPress网站以及该用户的元信息。
  5. When Azure function receives this GET request, it processes the info, takes out what I need to keep in the MongoDB Atlas Cluster and forms a JavaScript object ready to be saved in the DB.

    当Azure函数收到此GET请求时,它将处理信息,取出我需要保留在MongoDB Atlas群集中的内容,并形成一个准备保存在数据库中JavaScript对象。
  6. The azure function then connects to MongoDB Atlas instance via an npm package called mongoose, where after connecting the database, I create a DB Model/Schema, and then this data is saved to the MongoDB Atlas Cluster.

    然后,azure函数通过名为mongoose的npm软件包连接到MongoDB Atlas实例,在该数据库中,在连接数据库之后,我创建了一个数据库模型/架构,然后将这些数据保存到MongoDB Atlas集群。
  7. After which Azure function kind of sits there waiting for next sale to happen, where my client only pays for the execution time and amount of executions for Azure functions. (1 million of which are free every month ?).

    之后,Azure函数就坐在那里等待下次销售,我的客户只为Azure函数的执行时间和执行量付费。 ( 每月有100万免费吗?)。

Now, this is only a high-level summary of what’s happening, there’s a lot of steps that I skipped here like authentication which is beyond the scope of this article. You should always setup authentication and verification to keep things civil and avoid any overage.

现在,这只是正在发生的事情的简要概述,在此跳过了很多步骤,例如身份验证,这超出了本文的范围。 您应该始终设置身份验证和验证,以使事情保持文明状态并避免任何超额费用。

So, let’s go ahead and build this thing.

因此,让我们继续构建这个东西。

步骤#1:设置Microsoft Azure和VSCode (Step #1: Set up Microsoft Azure & VSCode)

I expect you to have the Azure account set up on your end. You’ll need to subscribe with a credit-card since we need storage for hosting the Node.js files which will be used with Azure Functions and you have to pay for storage (you’ll probably get a free $200 credit for the first month and even after that the cost is quite pretty low).

我希望您最终可以设置Azure帐户。 您需要使用信用卡进行预订,因为我们需要用于托管将与Azure Functions一起使用的Node.js文件的存储空间,而且您还必须支付存储空间的费用(第一个月您可能会获得200美元的免费赠送金额,甚至在那之后成本也相当低)。

So, go ahead and set up the following:

因此,继续进行以下设置:

  1. ✅ Setup a Microsoft Azure account with a credit card in billing.

    ✅在帐单中使用信用卡设置Microsoft Azure帐户。
  2. ✅ Install Visual Studio Code (Psst. I’m making a course on VSCode).

    ✅安装Visual Studio代码 (很抱歉,我正在上VSCode课程 )。
  3. ✅ Install the Azure Functions extension on your VSCode.

    ✅在VSCode上安装Azure Functions扩展 。
  4. ? To enable local debugging, install the Azure Functions Core Tools.

    ? 若要启用本地调试,请安装Azure Functions核心工具 。
  5. ? Create a new directory and open it up in VSCode.

    ? 创建一个新目录并在VSCode中打开它。

In case you’re wondering which theme and font I am using, it’s Shades of Purple ? — for more info see which software and hardware I use.

如果您想知道我使用的是哪种主题和字体,那就是Shades of Purple吗? —有关更多信息,请参阅我使用的软件和硬件 。

mongodb atlas_具有MongoDB Atlas,Microsoft Azure和无服务器功能的自定义WordPress仪表盘!..._第7张图片

步骤2:创建新功能的App项目 (Step #2: Create a New Function App Project)

Now let’s create a new function app project. This is really easy with VSCode. All you have to do is go-to the Azure Extension explorer present in the activity bar. From there access FUNCTIONS tab and click on the first Create New Project icon.

现在,让我们创建一个新的功能应用程序项目。 使用VSCode确实很容易。 您所要做的就是转到活动栏中显示的Azure Extension Explorer。 从那里访问“ FUNCTIONS选项卡,然后单击第一个“ Create New Project图标。

This will create a demo project, with basic files required to get started and will initialize a Git repo for you. I’ll keep up with small gif based demos to make things easier for you.

这将创建一个演示项目,其中包含入门所需的基本文件,并将为您初始化Git存储库。 我会跟上基于gif的小型演示,以使您更轻松。

步骤#3:创建HTTP触发的Azure函数 (Step #3: Create an HTTP-triggered Azure Function)

Now that we have created a function app project, let’s create an HTTP-triggered serverless Azure function. For that, go-to the Azure Extension explorer present in the activity bar. From there access FUNCTIONS tab and click on the second icon Create Function.

现在,我们已经创建了一个功能应用程序项目,让我们创建一个HTTP触发的无服务器Azure功能。 为此,转到活动栏中显示的Azure扩展资源管理器。 从那里访问“ FUNCTIONS选项卡,然后单击第二个图标“ Create Function

For the sake of this demo, I am choosing to keep the authentication part simple so going to select anonymous access. The name of our Azure function is HttpTriggerJS so you can find a new directory created with that name inside your project. This should contain two files i.e. functions.json and index.js

为了这个演示,我选择保持身份验证部分简单,以便选择匿名访问。 我们的Azure函数的名称是HttpTriggerJS因此您可以在项目中找到使用该名称创建的新目录。 这应该包含两个文件,即functions.jsonindex.js

⚡ A function is a primary concept in Azure Functions. You write code for a function in a language of your choice and save the code and configuration files in the same folder.

函数是Azure Functions中的主要概念。 您可以使用所选的语言编写功能代码,然后将代码和配置文件保存在同一文件夹中。

? The configuration is named function.json, which contains JSON configuration data. It defines the function bindings and other configuration settings. The runtime uses this file to determine the events to monitor and how to pass data into and return data from function execution. Read more on this file in the official documentation here.

? 该配置名为function.json ,其中包含JSON配置数据。 它定义了功能绑定和其他配置设置。 运行时使用此文件来确定要监视的事件,以及如何将数据传递到函数执行中以及从函数执行中返回数据。 在此处的官方文档中了解有关此文件的更多信息 。

Following is an example function.json file that gets created.

以下是创建的示例function.json文件。

{
  "disabled": false,
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}

And then, there’s an index.js file which contains a basic code that you can use to test your Azure function. It receives a parameter name and prints it back to you or shows you an error asking for this parameter.

然后,有一个index.js文件,其中包含可用于测试Azure函数的基本代码。 它会收到一个参数name然后将其打印回给您,或者显示询问该参数的错误。

module.exports = function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    if (req.query.name || (req.body && req.body.name)) {
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: "Hello " + (req.query.name || req.body.name)
        };
    }
    else {
        context.res = {
            status: 400,
            body: "Please pass a name on the query string or in the request body"
        };
    }
    context.done();
};

步骤#4:部署和测试您的Azure功能 (Step #4: Deploy & Test Your Azure Function)

Now that we have created an Azure function which can be triggered by GET HTTP request, let’s go ahead and deploy it with VSCode and test it with Postman API Explorer.

现在,我们已经创建了可以由GET HTTP请求触发的Azure函数,让我们继续使用VSCode进行部署,并使用Postman API Explorer对其进行测试。

To deploy the function go-to the Azure Extension explorer present in the activity bar. From there access FUNCTIONS tab and click on the third icon Deploy to Function App.

若要部署该功能,请转到活动栏中存在的Azure扩展资源管理器。 从那里访问FUNCTIONS选项卡,然后单击第三个图标Deploy to Function App

This will ask you a bunch of questions about what is the name of your app, use anything unique. I used demo-wp-mdb-azure— VSCode then use this to create a resource group, to group together your function-app related resources, it’s storage (used to save the files), and the created Azure function — finally responding us back with a public URL.

这将询问您有关应用程序名称的问题,请使用唯一的名称。 我使用了demo-wp-mdb-azure -VSCode,然后使用它来创建资源组,将与功能应用相关的资源分组在一起,将其存储(用于保存文件)和创建的Azure函数-最终将我们回复带有公共网址。

I then went ahead to access this URL and it asked for the name param as per the code then when I sent the name param with the Postman app, it responded with Hello Ahmad Awais. ?

然后,我继续访问此URL,并按代码要求输入name param,然后当我用Postman应用程序发送name param时,它用Hello Ahmad Awais响应。 ?

VSCode also asked me to update the function extension app verions to beta, and I chose yes — coz that will help me use Node.js v8 for async/await.

VSCode还要求我将功能扩展应用程序版本更新为Beta,我选择了yes,因为这将有助于我将Node.js v8用于异步/等待。

步骤#5:创建package.json并安装mongoose (Step #5: Create package.json and Install mongoose)

Now that our Azure function is up and running. Let’s create a package.json file in the root of our project and install mongoose. We’ll need this to connect and save data to our MongoDB Atlas Cluster.

现在我们的Azure功能已启动并正在运行。 让我们在项目的根目录中创建一个package.json文件并安装mongoose 。 我们需要它来连接数据并将其保存到我们的MongoDB Atlas集群。

Mongoose provides a straight-forward, schema-based solution to model your application data. It includes built-in typecasting, validation, query building, business logic hooks and more, out of the box. It’s pretty awesome. ?

Mongoose提供了一个直接的,基于模式的解决方案来对您的应用程序数据进行建模。 它包括现成的内置类型转换,验证,查询构建,业务逻辑挂钩等等。 太棒了 ?

步骤#6:为MongoDB连接添加应用程序设置 (Step #6: Add App Setting for MongoDB Connection)

Now we are almost ready to start writing code for our application. But before doing that, we’ll need a connection string to be able to connect to our MongoDB Atlas Cluster (just like we did with MongoDB Compass). This connection string is private and you shouldn’t commit it to the git repo.

现在我们几乎准备开始为我们的应用程序编写代码。 但在此之前,我们需要一个连接字符串才能连接到我们的MongoDB Atlas集群(就像我们使用MongoDB Compass一样)。 此连接字符串是私有的,您不应将其提交到git repo。

? This connections string belongs to the local.settings.json file in the project root. Let’s first download the settings, then add MongodbAtlas setting with our connection string (get this string from the MongoDB Atlas dashboard) and upload the app settings.

? 此连接字符串属于项目根目录中的local.settings.json文件。 首先,让我们下载设置,然后将MongodbAtlas设置添加到我们的连接字符串中(从MongoDB Atlas仪表板获取此字符串)并上传应用程序设置。

To do this, go-to the Azure Extension explorer present in the activity bar. From there access FUNCTIONS tab and select your subscription, then your Azure function app, i.e., demo-wp-mdb-azure and then right click Application Settings to select Download remote settings… to download and Upload local settings… to upload the settings after adding the MongodbAtlas connection string to the settings.

为此,请转到活动栏中显示的Azure扩展资源管理器。 从那里访问“ FUNCTIONS选项卡并选择您的订阅,然后选择您的Azure功能应用程序,即demo-wp-mdb-azure ,然后右键单击“ Application Settings以选择“ Download remote settings… Application Settings ,然后选择“ Upload local settings…以上传设置将MongodbAtlas连接字符串设置为设置。

步骤#7:更新Azure功能的节点版本 (Step #7: Update Node Version of Azure Function)

In the code, I intend to use async/await which are not available on v6.5.0 of Node.js that comes with the default version 1 of Azure functions. In the step #4, VSCode asked me to update to the runtime version of Azure function to beta and I did that. This enables support for latest Node.js versions on Azure functions.

在代码中,我打算使用async / await ,这在Azure版本的默认版本1附带的Node.js v6.5.0上不可用。 在第4步中,VSCode要求我将Azure函数的运行时版本更新为beta,而我做到了。 这样可以支持Azure功能上的最新Node.js版本。

So, let’s just update WEBSITE_NODE_DEFAULT_VERSION app setting in our local settings and update that to the remote settings.

因此,我们只需要在本地设置中更新WEBSITE_NODE_DEFAULT_VERSION应用设置并将其更新为远程设置即可。

步骤#8:创建MongoDB模型/架构 (Step #8: Create MongoDB Model/Schema)

Before we save any data to our MongoDB Atlas Cluster, let’s create a modelSale.js file that will contain the model’s schema for what we intend to save in the database. It’s an extremely simple schema implementation, I suggest you read up on what you can do here with [mongoose](http://mongoosejs.com/docs/guide.html) and MongoDB.

在将任何数据保存到MongoDB Atlas集群之前,让我们创建一个modelSale.js文件,其中将包含我们要保存在数据库中的模型的架构。 这是一个非常简单的架构实现,建议您阅读有关[mongoose](http://mongoosejs.com/docs/guide.html)和MongoDB可以在此处进行的操作的内容。

This file is pretty much self-explanatory.

该文件几乎是不言自明的。

/**
 * Model: Sale
 */
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;

// Sale Schema.
const saleSchema = new mongoose.Schema({
    sale_gross: Number,
    earnings: Number,
    currency: String,
    memberSince: Date,
    customerEmail: String,
    event_time: {
        type: Date,
        default: Date.now
    },
});


// Export the model.
module.exports = mongoose.model('Sale', saleSchema);

步骤#9:使用Node.js编写⚡Azure函数 (Step #9: Code the ⚡Azure Function with Node.js)

Now let’s code our Azure function. I’m adding all the main code lives inside the index.js file for the purpose of this demo. Also going to use the context object as the first parameter, make sure you read about that. Everything else is explained in the code snippet below.

现在,让我们编写Azure函数的代码。 为了这个演示的目的,我将所有主要代码添加到index.js文件中。 同样要使用上下文对象作为第一个参数,请确保已阅读有关内容 。 其他所有内容都在下面的代码片段中进行了说明。

So, this is just a demo code for this article. It does the following:

因此,这只是本文的演示代码。 它执行以下操作:

  • ✅ Gets the data from Paddle.com

    from从Paddle.com获取数据
  • ⚡ Connects to the MongoDB Atlas via connection string that we added in our Application Settings.

    ⚡通过我们在应用程序设置中添加的连接字符串连接到MongoDB Atlas。
  • ? Uses the defined DB schema inside the test database where it creates a sales collection including documents for our sales.

    ? 在test数据库中使用定义的数据库模式,在数据库中创建sales集合,包括我们销售的文档。
  • ⚙ Validates the data and creates a finalData object that gets saved in the MongoDB Atlas Cluster. Yay!!!

    ates验证数据并创建一个finalData对象,该对象将保存在MongoDB Atlas集群中。 好极了!!!
  • ? Finally, responds to the Paddle webhook with 200 status code if all goes well, and does the context.done() dance.

    ? 最后,如果一切顺利,对Paddle Webhook响应200状态代码,然后执行context.done()

Everything is pretty much explained with inline documentation.

内联文档几乎解释了所有内容。

/**
 * Azure Function: Sale.
 *
 * Gets data from Paddle.com (which in turn gets data
 * from WordPress) and processes the data, creates a
 * finalData object and saves it in MongoDB Atlas.
 *
 * @param context To pass data between function to / from runtime.
 * @param req HTTP Request sent to the Azure function by Paddle.
 */
module.exports = async function (context, req) {
    // Let's call it log.
    const log = context.log;

    // Log the entire request just for the demo.
    log('[RAN] RequestUri=%s', req.originalUrl);

    /**
     * Azure function Response.
     *
     * Processes the `req` request from Paddle.com
     * and saves the data to MongoDB Atlas while
     * responding the `res` response.
     */

    // Database interaction.
    const mongoose = require('mongoose');
    const DATABASE = process.env.MongodbAtlas;

    // Connect to our Database and handle any bad connections
    mongoose.connect(DATABASE);
    mongoose.Promise = global.Promise; // Tell Mongoose to use ES6 promises
    mongoose.connection.on('error', (err) => {
        context.log(`ERROR→ ${err.message}`);
    });

    // Sale Schema.
    require('./modelSale');
    const Sale = mongoose.model('Sale');

    // Create a Response.
    if (req.query.customFieldName) { // Simple authentication for the purpose of demo.

        // Build the data we need.
        const sale_gross = req.query.p_sale_gross || '0';
        const earnings = JSON.parse(req.query.p_earnings)['16413'] || '0'
        const currency = req.query.p_currency || 'USD';
        const memberSince = req.query.memberSince || new Date();
        const customerEmail = req.query.customerEmail || '';
        const event_time = new Date();

        log('[OUTPUT]—— sale_gross: ' + sale_gross);
        log('[OUTPUT]—— earnings: ' + earnings);
        log('[OUTPUT]—— currency: ' + currency);

        const finalData = {
            sale_gross: sale_gross,
            earnings: earnings,
            currency: currency,
            memberSince: memberSince,
            customerEmail: customerEmail,
            event_time: event_time,
        }

        // Save to db.
        const sale = await (new Sale(finalData)).save();
        log("[OUTPUT]—— SALE SAVED: ", sale);

        // Respond with 200.
        context.res = {
            status: 200,
            body: "Thank You for the payment! " + (req.query.customFieldName || req.body.customFieldName)
        };
    } else {
        context.res = {
            status: 400,
            body: "Please pass a name on the query string or in the request body"
        };
    }


    // Informs the runtime that your code has finished. You must call context.done, or else the runtime never knows that your function is complete, and the execution will time out.
    // @link: https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node#contextdone-method
    context.done();
};

步骤#10:重新部署Azure功能 (Step #10: Re-Deploy The Azure Function)

Now let’s re-deploy the Azure function. For that, go-to the Azure Extension explorer present in the activity bar. From there access FUNCTIONS tab and click on the third Deploy to Function App icon.

现在,让我们重新部署Azure功能。 为此,转到活动栏中显示的Azure扩展资源管理器。 从那里访问FUNCTIONS选项卡,然后单击第三个Deploy to Function App图标。

>

步骤#11:通过Paddle的Webhook测试Azure功能 (Step #11: Test Azure Function via Paddle’s Webhook)

Looks like we’re pretty much done. All that’s left is to test our Azure function by triggering a dummy webhook via Paddle.com. Let’s do that. Also, when things do work, let’s explore how our data looks in the MongoDB Compass.

看起来我们已经完成了。 剩下的就是通过Paddle.com触发虚拟webhook来测试我们的Azure功能。 来做吧。 此外,当一切正常时,让我们探索一下数据在MongoDB Compass中的外观。

Wow, Humph!!! That was a lot. Glad it worked. ?

哇,哼! 好多 很高兴它起作用。

? 那么,刚刚发生了什么? ( ? So, What Just Happened?! )

Prepare yourself for a mouthful. I created a small part of the Sales module in the custom WordPress Dashboard app that I am building. I used MongoDB Atlas and Compass, then created Microsoft ⚡Azure Function via Function App with VSCode, deployed the app with env secret as application string with the MongoDB connection string, updated the Node.js version and triggered the function via a dummy webhook from Paddle.com (like it will trigger when a sale happens) to send data (from Paddle + WordPress) to our Azure function and from there to MongoDB Atlas. And it worked, haha!

准备一口。 我在正在构建的自定义WordPress仪表板应用程序中创建了Sales模块的一小部分。 我使用了MongoDB Atlas和Compass,然后通过带有VSCode的Function App创建了Microsoft⚡AzureFunction,使用env secret作为MongoDB连接字符串的应用程序字符串部署了带有env secret的应用程序,更新了Node.js版本,并通过Paddle中的虚拟webhook触发了该函数.com(当交易发生时,它会触发)将数据(从Paddle + WordPress)发送到我们的Azure函数,再从那里发送到MongoDB Atlas。 它奏效了,哈哈!

机器学习与人工智能 ( Machine Learning & Artificial Intelligence )

Machine learning and artificial intelligence are always a mesmerizing topic in the world of software technology but we don’t talk a lot about that in the context of WordPress or in the WP Community.

机器学习和人工智能在软件技术领域一直是一个令人着迷的话题,但是在WordPress或WP社区中,我们并没有谈论太多。

I set to change that by adding a few small improvements to a select few WordPress sites for my client and have every intention of exploring the same with this custom WordPress dashboard.

我打算通过为我的客户选择的几个WordPress网站添加一些小的改进来改变这种状况,并打算使用此自定义WordPress仪表板进行相同的探索。

I have discussed this topic before and shared what I am working on, take a look at this small artificial intelligence plugin I am building for WordPress, and integrating it with different Azure Cognitive Services.

我之前已经讨论过该主题,并分享了我的工作,看一下我为WordPress构建的这个小型人工智能插件,并将其与其他Azure认知服务集成。

I explained this in a video in another post that you can find here: Building A WordPress Artificial Intelligence Plugin →

我在另一篇帖子的视频中对此进行了解释,您可以在此处找到: 构建WordPress人工智能插件→

I’ve accomplished similar results in this dashboard by the wpapi package. First I upload the image to cognitive services and then on a confident response, I send it to WordPress to uploaded via WordPress REST API, with image description that gets generated by Computer Vision AI.

我通过wpapi软件包在此仪表板中实现了类似的结果。 首先,我将图像上传到认知服务,然后在做出肯定的响应后,将其发送到WordPress,然后通过WordPress REST API上载,图像描述由Computer Vision AI生成。

/**
 * Get Image Alt Recognition with Computer Vision
 * using Azure Cognitive Services.
 */
var WPAPI = require('wpapi');
var wp = new WPAPI({
    endpoint: 'http://src.wordpress-develop.dev/wp-json'
});

/**
 * Handle Image Alt Generation.
 */
function processImage() {
    // **********************************************
    // *** Update or verify the following values. ***
    // **********************************************

    // Replace  with your valid subscription key.
    var subscriptionKey = "";

    // You must use the same region in your REST call as you used to get your
    // subscription keys. For example, if you got your subscription keys from
    // westus, replace "westcentralus" in the URI below with "westus".
    //
    // Free trial subscription keys are generated in the westcentralus region.
    // If you use a free trial subscription key, you shouldn't need to change
    // this region.
    var uriBase =
        "https://westcentralus.api.cognitive.microsoft.com/vision/v2.0/analyze";

    // Request parameters.
    var params = {
        "visualFeatures": "Categories,Description,Color",
        "details": "",
        "language": "en",
    };

    // Display the image.
    var sourceImageUrl = document.getElementById("inputImage").value;
    document.querySelector("#sourceImage").src = sourceImageUrl;

    // Make the REST API call.
    $.ajax({
            url: uriBase + "?" + $.param(params),

            // Request headers.
            beforeSend: function (xhrObj) {
                xhrObj.setRequestHeader("Content-Type", "application/json");
                xhrObj.setRequestHeader(
                    "Ocp-Apim-Subscription-Key", subscriptionKey);
            },

            type: "POST",

            // Request body.
            data: '{"url": ' + '"' + sourceImageUrl + '"}',
        })

        .done(function (data) {
            // Show formatted JSON on webpage.
            $("#responseTextArea").val(JSON.stringify(data, null, 2));

            // Extract and display the caption and confidence from the first caption in the description object.
            if (data.description && data.description.captions) {
                var caption = data.description.captions[0];

                if (caption.text && caption.confidence >= 0.5) {
                    const imgDescription = caption.text;

                    // ⬆️ Upload to WordPress.
                    wp.media()
                        // Specify a path to the file you want to upload, or a Buffer
                        .file(sourceImageUrl)
                        .create({
                            title: imgDescription,
                            alt_text: imgDescription,
                            caption: imgDescription,
                            description: imgDescription
                        })
                        .then(function (response) {
                            // Your media is now uploaded: let's associate it with a post
                            var newImageId = response.id;
                            return wp.media().id(newImageId).update({
                                post: associatedPostId
                            });
                        })
                        .then(function (response) {
                            console.log('Media ID #' + response.id);
                            console.log('is now associated with Post ID #' + response.post);
                        });
                }
            }
        })

        .fail(function (jqXHR, textStatus, errorThrown) {
            // Display error message.
            var errorString = (errorThrown === "") ? "Error. " :
                errorThrown + " (" + jqXHR.status + "): ";
            errorString += (jqXHR.responseText === "") ? "" :
                jQuery.parseJSON(jqXHR.responseText).message;
            alert(errorString);
        });
};

? 内容审核自动化 (? Content Moderation Automation)

One of the ideas we have is to put AI/ML from Azure to use as a content moderation platform which offers a built-in human-in-the-loop + machine learning to help moderate images, text, and videos. It’s a work in progress but it’s something really interesting that you should definitely take a look at.

我们的想法之一是将Azure的AI / ML用作内容审核平台 ,该平台提供内置的“环环相扣+机器学习”功能,以帮助缓和图像,文本和视频。 这是一个正在进行的工作,但是您绝对应该看一下它,这确实很有趣。

mongodb atlas_具有MongoDB Atlas,Microsoft Azure和无服务器功能的自定义WordPress仪表盘!..._第8张图片

? WordPress语法(纳粹)情报 (? WordPress Grammar (Nazi) Intelligence)

Y’all have a habit of typing the typos over and over again. I do that all the time. The coolest thing ever is when search engines like Bing and Google can spell check and proofread the search query for you.

你们都有习惯一遍又一遍地输入错字。 我一直都这样。 有史以来最酷的事情是Bing和Google等搜索引擎可以为您拼写检查并校对搜索查询。

What if WordPress had that?! — So, I got to work and ended up cooking the same functionality in the WordPress admin area for when you type a typo in your post title or more than one typos for what I care.

如果WordPress有该怎么办? —因此,我开始工作,最终在WordPress管理员区域中使用了相同的功能,以便您在帖子标题中输入错字或为我所关心的内容输入多个错字。

I was so excited that I couldn’t contain myself, so there’s me in the left bottom corner. All happy and surprised! ??????☝??

我非常激动,无法抑制自己,所以在左下角有我。 所有人高兴和惊讶! ??????☝??

轮到你了! ( It’s Your Turn Now! )

I really hope that you enjoyed this potential integration between all these modern JavaScript frameworks, AI/ML products, and serverless functions.

我真的希望您喜欢所有这些现代JavaScript框架,AI / ML产品和无服务器功能之间的潜在集成。

This project is a lot of fun. I think if you give this tech-stack a shot you can have this crazy amount of fun as well. So, leaving it up to you to try MongoDB Atlas, in the context of WordPress — and maybe attach all that to a bunch of serverless functions.

这个项目很有趣。 我认为,如果您给这个技术栈一个机会,您也可以拥有如此疯狂的乐趣。 因此,让您自己尝试在WordPress的上下文中尝试MongoDB Atlas ,并将所有这些附加到一堆无服务器功能上。

It’d mean a lot to me if you share this post on Twitter →
Also feel free to say ? to me there at @MrAhmadAwais.

如果您在Twitter上分享这篇文章,这对我来说意义重大
还可以随意说吗? 我在@ MrAhmadAwais那里 。

Peace! ✌

和平! ✌

翻译自: https://scotch.io/tutorials/a-custom-wordpress-dashboard-with-mongodb-atlas-microsoft-azure-serverless-functions

mongodb atlas

你可能感兴趣的:(mongodb atlas_具有MongoDB Atlas,Microsoft Azure和无服务器功能的自定义WordPress仪表盘!...)