mongodb 自定义id_使用MongoDB,Azure和无服务器功能构建自定义仪表板

mongodb 自定义id

本文最初在Ahmad Awais上发表。 感谢您支持使SitePoint成为可能的合作伙伴。

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

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


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

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

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

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

自定义WordPress仪表板目标

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

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

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

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

👀高级数据报告

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

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

⚡无服务器自动化

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

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

🔥物联网中心

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

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

🤖机器学习与人工智能

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

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

免费学习PHP!

全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。

原价$ 11.95 您的完全免费

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

🕰实时直播

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

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

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

MongoDB和MongoDB Atlas

对于此自定义WordPress仪表板,我将MongoDB Atlas用作DBaaS(数据库即服务)。 而且我再也不能快乐了。 当我第一次分享我将使用MongoDB时,许多开发人员都对此感到担忧。

Mongodb

大多数问题问为什么我要通过添加另一个数据库来增加另一层复杂性。 为什么不按原样使用WordPress数据库? 为了回答这些问题,我准备了为什么要使用MongoDB Atlas的原因列表。

♨不喜欢RDBMS

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

💸硬盘便宜-CPU / RAM却不便宜

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

如今,磁盘空间非常便宜。 另一方面,CPU / RAM不是,如果您在此处选择不正确,您的系统管理员成本会Swift飙升。

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

🍀MongoDB的优点

  • 无模式 。 获胜的灵活模式。 我不需要更改任何东西,我的常规应用程序开发工作流程,创建了一个我要处理的基于JSON类型数据的基于Node.js的应用程序,我可以将其输入到MongoDB中并且可以正常工作。
  • 工作流一致性 。 以表示我的自定义仪表板的方式创建文档。 销售,视频,演讲,评论,评论,注册等在前端和后端(甚至在数据库中)都具有相似的数据表示。 我通过中间件管理第三者数据。 这种一致性转化为干净的代码。
  • 易于横向扩展 。 它通过使用副本集扩展读取。 通过使用分片(自动平衡)缩放写入。 只需启动另一台机器,然后您就可以离开。 最重要的是,除了通过RDBMS进行垂直扩展外,MongoDB还允许您以不同的一致性级别进行水平扩展。 这是一大优势。 ➕
  • 费用 。 当然取决于哪个RDBMS,但是MongoDB是免费的,可以在Linux上运行,非常适合在便宜的商品套件上运行。

🍃为什么选择MongoDB Atlas

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

蒙古语地图集

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

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

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

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

🔋MongoDB指南针

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

Mongodb指南针

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

  • 可视化和探索:查看数据库,了解事物的外观,甚至可视化诸如地图/坐标的内容。
  • 插入,修改和删除:您还可以直接从MongoDB指南针对数据库执行CRUD操作。 使测试更加容易。
  • 调试和优化:最后,对数据进行分析,调试,甚至在数据库的出色GUI内查找性能问题。 如果您使用MongoDB,则此工具是必备工具。
  • 可扩展:最好的部分是您可以构建自己的插件来扩展MongoDB Compass。 这是有关构建自己的Compass插件的文档。
  • 企业风格:MongoDB Compass有以下几种风格:社区(免费)和企业(许可)-企业版是使您可视化数据库架构的版本。

Mon MongoDB Atlas入门

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

步骤#1:转到MongoDB地图集→

转到MongoDB Atlas网站并注册AWS托管的完全免费的MongoDB实例,该实例具有共享RAM和512 MB存储。 单击免费入门按钮。

蒙古语地图集

步骤#2:在MongoDB Atlas上注册

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

Mongodb Atlas注册

步骤#3:创建集群

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

Mongodb Atlas创建集群

步骤#4:创建数据库用户名和密码

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

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

GIF for MongoDB Atlas,Microsoft Azure和无服务器功能

步骤5:将IP添加到白名单以进行访问

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

所以,再次,头部到安全 > IP白名单 ,然后点击右侧的+添加IP地址按钮,最后允许访问从任何地方按钮允许匿名访问。

GIF for MongoDB Atlas,Microsoft Azure和无服务器功能

步骤#6:通过MongoDB Compass连接

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

转到“ 连接”,然后选择“ 使用MongoDB Compass连接”,如果尚未下载,则下载Compass。 复制URI连接字符串。 最后,打开Compass,它应该能够检测剪贴板中的连接字符串,并允许其连接到数据库。

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

GIF for MongoDB Atlas,Microsoft Azure和无服务器功能

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

WordPress REST API-FTW!

这个基于WordPress的Node.js自定义仪表板通过WordPress REST API与WordPress实例进行交互。 由于这是一个Node.js应用程序,因此我使用的是由K Adam White编写的很棒的库wpapi 。 他还构建了一个基于Express Express的演示WordPress应用程序。 这就是我构建此自定义仪表板时的灵感来源,因此您将在此处看到很多内容。

Express基于Express的 WordPress自定义路由器

路由器设置有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;

查看Gist上的代码。

🎚基于基本Express的实现

我没有将整个事情托管在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;

查看Gist上的代码。

🦏身份验证已完成

对于此设置,您还需要通过向其提供身份验证数据来对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;

查看Gist上的代码。

🦁网站内容累积

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

  • 分页集合的所有页面。
  • 您的WordPress网站信息。
  • 按字母顺序排列的类别列表。
  • 内容缓存中的特定类别(由slug指定)。
  • 标签的字母顺序列表。
  • 内容缓存中的特定标签(由slug指定)
  • 与WP具有某些功能相等的其他内容。

此代码看起来像这样。

'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
};

查看Gist上的代码。

🛠自定义路线和销售数据

最后,我已经按照许多自定义路线进行烹饪,可以从中获取任何与销售相关的数据。 对于已有的特定体系结构,为了方便和并行起见,我再次使用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 );
});

查看Gist上的代码。

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

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

// Query Parameters & Filtering Custom Routes.
site.handler = site.registerRoute( 'sales/v1', 'receipts/(?P<id>)', {
    // 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.

查看Gist上的代码。

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

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

Microsoft Azure和Azure功能

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

👀三种选择

目前有三个主要的云服务提供商。 它们是Microsoft AzureGoogle Cloud PlatformAmazon Web Services 。 每个功能都有可用的无服务器功能,分别称为Azure功能,GCP Cloud功能和AWS Lambda。

Azure选择Azure

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

同样,我们使用Azure ML Studio,AI认知服务和虚拟机托管该项目的一部分这一事实,意味着将Azure函数用于无服务器体系结构完全有意义。

Azure函数入门

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

are我们正在建造什么?

  1. 我正在构建一个基于JavaScript的无服务器Azure函数,尤其是基于Node.js代码。
  2. 来自我们的第三方付款解决方案(即Paddle.com)的简单GET HTTP请求将触发该Azure功能。
  3. Paddle.com上的交易一旦发生,它将触发一个 Webhook,其中包含与我们的销售,数量,项目,收入以及WordPress发送给Paddle的一些与会员有关的数据有关的信息。
  4. 使用WordPress REST API,我添加了一些与购买该产品的用户有关的自定义数据,例如WordPress DB中的用户ID,该销售的WordPress网站以及该用户的元信息。
  5. 当Azure函数接收到此GET请求时,它将处理信息,取出我需要保留在MongoDB Atlas群集中的内容,并形成一个准备保存在数据库中JavaScript对象。
  6. 然后,Azure函数通过一个名为mongoose的npm软件包连接到MongoDB Atlas实例,在该数据库中,在连接数据库之后,我创建一个数据库模型/架构,然后将这些数据保存到MongoDB Atlas群集。
  7. 之后,Azure函数就坐在那里等待下次销售,我的客户只为Azure函数的执行时间和执行量付费。 ( 每月有100万免费 )😮。

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

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

步骤#1:设置Microsoft Azure和VSCode

我希望您最终可以设置Azure帐户。 您需要使用信用卡进行预订,因为我们需要用于托管Node.js文件的存储空间,该文件将与Azure Functions一起使用,并且您需要付费进行存储(第一个月您可能会获得200美元的免费信用额度,甚至之后的费用也很低)。

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

  1. ✅在帐单中使用信用卡设置Microsoft Azure帐户。
  2. ✅安装Visual Studio代码 (很抱歉,我正在上VSCode课程 )。
  3. ✅在VSCode上安装Azure Functions扩展
  4. 💡若要启用本地调试,请安装Azure Functions核心工具
  5. 🗂创建一个新目录并在VSCode中打开它。

如果您想知道我使用的是哪种主题和字体,那就是“紫色阴影”💜-有关更多信息,请参阅我使用的软件和硬件

7 VSCode紫色阴影

步骤2:创建新功能的App项目

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

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

GIF for MongoDB Atlas,Microsoft Azure和无服务器功能

步骤#3:创建HTTP触发的Azure函数

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

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

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

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

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

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

查看Gist上的代码。

然后,有一个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();
};

查看Gist上的代码。

GIF for MongoDB Atlas,Microsoft Azure和无服务器功能

步骤#4:部署和测试您的Azure功能

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

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

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

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

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

步骤#5:创建package.json并安装mongoose

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

Mongoose为基于应用程序数据的建模提供了一个简单,基于架构的解决方案。 它包括现成的内置类型转换,验证,查询构建,业务逻辑挂钩等等。 太棒了 💯

GIF for MongoDB Atlas,Microsoft Azure和无服务器功能

步骤#6:为MongoDB连接添加应用程序设置

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

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

为此,请转到活动栏中的Azure扩展资源管理器。 从那里访问“ 功能”选项卡,选择您的订阅,然后选择您的Azure功能应用程序,即demo-wp-mdb-azure 。 在将MongodbAtlas连接字符串添加到设置后,右键单击“ 应用程序设置”,然后选择“ 下载远程设置...”以下载,并选择“ 上传本地设置”以上传设置。

步骤#7:更新Azure功能的节点版本

在代码中,我打算使用async / await ,这在Node.js v6.5.0(Azure函数的默认版本1附带)上不可用。 在步骤4中,VSCode要求我将Azure函数的运行时版本更新为beta,然后我执行了此操作。 这启用了对Azure函数上最新的Node.js版本的支持。

因此,让我们在本地设置中更新WEBSITE_NODE_DEFAULT_VERSION应用设置,并将其更新为远程设置。

GIF for MongoDB Atlas,Microsoft Azure和无服务器功能

步骤#8:创建MongoDB模型/架构

在将任何数据保存到MongoDB Atlas集群之前,让我们创建一个modelSale.js文件,其中将包含我们要保存在数据库中的模型的架构。 这是一个非常简单的架构实现,我建议您阅读一下在mongooseMongoDB上可以做什么。

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

/**
 * 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);

查看Gist上的代码。

步骤#9:使用Node.js编写Azure函数代码

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

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

  • from从Paddle.com获取数据
  • ⚡通过我们在应用程序设置中添加的连接字符串连接到MongoDB Atlas。
  • s在test数据库中使用定义的数据库模式,在该数据库中创建sales集合,包括销售文件。
  • ates验证数据并创建一个finalData对象,该对象将保存在MongoDB Atlas集群中。 好极了!
  • 🥅最后,如果一切顺利,以200状态代码响应Paddle Webhook,然后执行context.done()

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

/**
 * 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();
};

查看Gist上的代码。

步骤#10:重新部署Azure功能

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

GIF for MongoDB Atlas,Microsoft Azure和无服务器功能

步骤#11:通过Paddle的Webhook测试Azure功能

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

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

🤔那么,刚刚发生了什么?

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

机器学习与人工智能

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

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

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

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

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 <Subscription Key> with your valid subscription key.
    var subscriptionKey = "<Subscription Key>";

    // 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);
        });
};

查看Gist上的代码。

👀内容审核自动化

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

内容主持人框图

🕵WordPress语法(纳粹)情报

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

想象一下WordPress是否具有该功能? 因此,我开始工作,最终在WordPress管理区域中使用了相同的功能,以便您在帖子标题中键入拼写错误(或者,我关心的所有错别字都是!)。

WordPress AI自动标题校正校对和拼写检查建议

我非常激动,无法抑制自己,所以在左下角有我。 所有人高兴和惊讶! 🙌👐👏👊💪🎶☝😌🎧

轮到你了!

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

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

翻译自: https://www.sitepoint.com/build-custom-dashboards-with-mongodb-azure-serverless-functions/

mongodb 自定义id

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值