如何将会话数据存储到机器人生成器中的自定义存储中

how to store session data into custom storage in bot builder

我正在使用 node js 构建聊天机器人。

我目前正在将会话数据存储到 Microsoft 默认存储中,每个用户会话限制为 64K。我想使用自己的存储来存储会话数据。 Here 是我从微软开发者那里得到的帮助。

我能够存储在文档数据库和 Azure table。

不过,我还是很困惑。我们将如何实现 IStorageClient 接口以存储在自己的数据库中?

每当我设置 session.UserData.name="" 它应该存储在自己的数据库中。

我不确定我是否遇到了问题;我明白你想做什么,看来你已经准备好了所有的部分。

首先,您必须实现 IStorageClient 接口。在您的实施中,您编写了将内容存储在数据库中的逻辑。

您可以查看 DocumentDB and Azure Tables 实施以了解如何实施。

现在,问题是……如果您的自定义存储在 Azure 中……,那么您可以将 AzureBotStorage 与您的自定义存储客户端一起使用。您实例化您的自定义存储客户端,传递对 AzureBotStorage 的引用并将其设置为 bot

中的存储
// Azure DocumentDb State Store
var docDbClient = new azure.DocumentDbClient({
    host: process.env.DOCUMENT_DB_HOST,
    masterKey: process.env.DOCUMENT_DB_MASTER_KEY,
    database: process.env.DOCUMENT_DB_DATABASE,
    collection: process.env.DOCUMENT_DB_COLLECTION
});
var botStorage = new azure.AzureBotStorage({ gzipData: false }, docDbClient);

// Set Custom Store
bot.set('storage', botStorage);

如果您的自定义存储位于 Azure 以外的任何其他位置,那么 AzureBotStorage 可能不适合您。请注意,我不确定这一点,您必须检查代码以确认。据我所见,它看起来非常通用,因此您可以重用它并实现 IStorageClient。如果不是这种情况,您还必须实现 IBotStorage 接口。

最后,AzureBotStorage 正在这样做。它实现 IBotStorage 并使用 IStorageClient 与实际提供者交互。

我编写了将机器人数据存储到 Mongo Db 中的代码。 完整代码和详细信息可以在 BotBuilder-MongoDB

中找到

IstorageClient 接口实现代码:

"use strict";
var Consts = require('./Consts');
var mongodb_1 = require("mongodb");
var replaceDot_Atrate = require("./replaceDot");
var mongoDbConnection = require('./connection.js');
var conf = require('../config');
var conversational_collname = conf.db.conversationalCollection;

var IStorageClient = (function () {

    function IStorageClient(options) {
        this.options = options;
    }

    IStorageClient.prototype.retrieve = function (partitionKey, rowKey, callback) {
        var id = partitionKey + ',' + rowKey;
        if(rowKey!=="userData"){
            var query={"$and":[{"userid":id}]}
                mongoDbConnection(function(err,db) {
                var iterator= db.collection(conversational_collname).find(query);
                iterator.toArray(function (error, result, responseHeaders) {
                    if (error) {
                        console.log("Error",error)
                        callback(error, null, null);
                    }
                    else if (result.length == 0) {
                        callback(null, null, null);
                    }
                    else {
                        var document_1 = result[0];
                        var finaldoc=replaceDot_Atrate.substituteKeyDeep(document_1, /\@/g, '.');
                        finaldoc["id"]=id
                        callback(null, finaldoc, null);
                    }
                });
            }); 
        }
        else{
            var query={"$and":[{"userid":partitionKey}]}
            mongoDbConnection(function(err,db) { 

                var iterator= db.collection(conversational_collname).find(query);
                iterator.toArray(function (error, result, responseHeaders) {
                    if (error) {
                        callback(error, null, null);
                    }
                    else if (result.length == 0) {
                        //console.log("result length 0")
                        callback(null, null, null);
                    }
                    else {
                        var document_1 = result[0];
                        callback(null, document_1, null);
                    }
                });
            });
        }
    };

    IStorageClient.prototype.initialize = function (callback) {
        var _this = this;
        var client=mongodb_1.MongoClient;
        this.client = client;

        mongoDbConnection(function(err,database) {    
                _this.database = database;
                _this.collection = database.collection(conversational_collname);
                callback(null);
         });
    };

    IStorageClient.prototype.insertOrReplace = function (partitionKey, rowKey, entity, isCompressed, callback) {
        var id=partitionKey + ',' + rowKey
        var docDbEntity = { id: partitionKey + ',' + rowKey, data: entity, isCompressed: isCompressed };
        if(rowKey!=="userData"){
            var newEntitiy=replaceDot_Atrate.substituteKeyDeep(entity, /\./g, '@');
            var conditions1 = {
                'userid': id
            };
            var updateobj1 = {
                "$set": {"data":newEntitiy,"isCompressed":false}
            };   
            mongoDbConnection(function(error,db) {    
                db.collection(conversational_collname).update(conditions1,updateobj1,{upsert: true},function(err,res){
                callback(error, null,"");
            });
            });
        }
        else{
            var conditions = {
                'userid': partitionKey
            };
            var update = {
                "$set": {"data":entity}
            }
            mongoDbConnection(function(error,db) {    
                db.collection(conversational_collname).update(conditions,update,{upsert: true},function(err,res){
                callback(error, null,"");
           })
        });
        } 
    };


    IStorageClient.getError = function (error) {
        if (!error)
            return null;
        return new Error('Error Code: ' + error.code + ' Error Body: ' + error.body);
    };

    return IStorageClient;
}());
exports.IStorageClient = IStorageClient;

这是该库的另一个版本:mongo-bot-storage

import {MongoDbBotStorage, MongoDBStorageClient} from "mongo-bot-storage";

// use it like this 
bot.set("storage", new MongoDbBotStorage(new MongoDBStorageClient({
    url: "mongodb://localhost/mydb",
    mongoOptions: {}
})));

// or like this
MongoClient.connect("mongodb://localhost/mydb", (error, db) => {
    bot.set("storage", new MongoDbBotStorage(new MongoDBStorageClient({db})));
});

然后使用默认的session.userData,等等

别忘了

// Enable Conversation Data persistence
bot.set('persistConversationData', true);

我将这个答案发布在一个非常非常旧的线程上,只是因为它似乎是为 Bot Framework 实现自定义存储选项的最佳结果。

有一个相当简单的解决方案,它不涉及使用一段时间未更新的 npm,这会带来企业环境无法审计的风险,或者会使您的控制台充满大量日志条目。

最简单的方法是按照此 Undocumented Guide for Custom Data Storage in Microsoft Bot Framework

中的步骤使用您选择的数据库的最新驱动程序为您的机器人创建您自己的数据存储代码

我花了大约一个小时为 MongoDB 实施,包括他们最新驱动程序的一些学习曲线。

简而言之,如果 link 在某个时候死了,您可以创建一个中间件来导出 Bot Framework 正在寻找的两个关键函数:getDatasaveData。其中每一个都必须具有以下粗略结构(来自 link 使用 Redis):

var storageKey = 'conversationId';
module.exports = {
getData : (data, callback) => {
    redisClient.get(data[storageKey], (err, reply) => {
        if (err || !reply) {
            callback(err, null);
        } else {
            callback(null, JSON.parse(reply));
        }
    })
},
saveData : (data, value, callback) => {
        redisClient.set(data[storageKey], JSON.stringify(value), (err, reply) => {
            if (err) {
                callback(err);
            } else if (reply === 'OK') {
                callback(null);
            }
        })
    }
}

然后,在你的app.js中,一定要require()你的中间件并相应地设置它:

const dbMiddleware = require('./path/to/middleware')

bot.set('storage', dbMiddleware)