如何在本地使用 MongoDB 和 directline-js 在使用 NodeJs 和 Mongoose 的 Bot Framework 中进行状态管理?

How to use MongoDB locally and directline-js for state management in Bot Framework using NodeJs and Mongoose?

我在 本地 MongoDB 存储中维护 bot 状态。当我尝试使用 directline-js 将对话 移交 agent 时,它显示BotFrameworkAdapter.sendActivity(): Missing Conversation ID 的错误。对话 ID 正在保存在 MongoDB

当我将中间层从 Array 更改为 MongoDB 时出现问题。我已经使用带有数组和默认内存存储的 directline-js 成功实现了相同的机器人-人类交接。

BotFramework 中的内存存储

const { BotFrameworkAdapter, MemoryStorage, ConversationState, UserState } = require('botbuilder')
const memoryStorage = new MemoryStorage();
conversationState = new ConversationState(memoryStorage);
userState = new UserState(memoryStorage);

传递给代理的中间层

case '#connect':
  const user = await this.provider.connectToAgent(conversationReference);
  if (user) {
             await turnContext.sendActivity(`You are connected to 
${ user.userReference.user.name }\n ${ JSON.stringify(user.messages) }`);

   await this.adapter.continueConversation(user.userReference, async 
   (userContext) => {
         await userContext.sendActivity('You are now connected to an agent!');
                    });
                    } 
   else {
 await turnContext.sendActivity('There are no users in the Queue right now.');
         }

this.adapter.continueConversation 在使用 MongoDB 时抛出错误。 在使用 Array 时,它可以正常工作 。 MongoDB 和 Array 对象在结构上都相似。

由于这适用于 MemoryStorage 而不是您的 MongoDB 实施,我猜您的 MongoDB 实施有问题。这个答案将集中于此。如果不是这种情况,请向您的存储库提供您的 MongoDb 实现 and/or 和 link,我可以解决这个问题。


仅当您想使用自定义 models/types/interfaces 时才需要 Mongoose。对于实现 BotState, you just need to write a custom Storage 适配器的存储。

are documented here 的基础知识。虽然是为 C# 编写的,但您仍然可以将这些概念应用于 Node。

1。安装 mongodb

npm i -S mongodb

2。创建 MongoDbStorage class 文件

MongoDbStorage.js

var MongoClient = require('mongodb').MongoClient;

module.exports = class MongoDbStorage {
    constructor(connectionUrl, db, collection) {
        this.url = connectionUrl;
        this.db = db;
        this.collection = collection;

        this.mongoOptions = {
            useNewUrlParser: true,
            useUnifiedTopology: true
        };
    }

    async read(keys) {
        const client = await this.getClient();
        try {
            var col = await this.getCollection(client);

            const data = {};
            await Promise.all(keys.map(async (key) => {
                const doc = await col.findOne({ _id: key });
                data[key] = doc ? doc.document : null;
            }));
            return data;
        } finally {
            client.close();
        }
    }

    async write(changes) {
        const client = await this.getClient();
        try {
            var col = await this.getCollection(client);

            await Promise.all(Object.keys(changes).map((key) => {
                const changesCopy = { ...changes[key] };
                const documentChange = {
                    _id: key,
                    document: changesCopy
                };
                const eTag = changes[key].eTag;

                if (!eTag || eTag === '*') {
                    col.updateOne({ _id: key }, { $set: { ...documentChange } }, { upsert: true });
                } else if (eTag.length > 0) {
                    col.replaceOne({ _id: eTag }, documentChange);
                } else {
                    throw new Error('eTag empty');
                }
            }));
        } finally {
            client.close();
        }
    }

    async delete(keys) {
        const client = await this.getClient();
        try {
            var col = await this.getCollection(client);

            await Promise.all(Object.keys(keys).map((key) => {
                col.deleteOne({ _id: key });
            }));
        } finally {
            client.close();
        }
    }

    async getClient() {
        const client = await MongoClient.connect(this.url, this.mongoOptions)
            .catch(err => { throw err; });

        if (!client) throw new Error('Unable to create MongoDB client');

        return client;
    }

    async getCollection(client) {
        return client.db(this.db).collection(this.collection);
    }
};

注意:我只对此进行了一些测试——足以使其与 the Multi-Turn-Prompt Sample 配合使用。使用风险自负,必要时进行修改。

我基于这三种存储实现的组合:

3。在你的机器人中使用它

index.js

const MongoDbStorage = require('./MongoDbStorage');

const mongoDbStorage = new MongoDbStorage('mongodb://localhost:27017/', 'testDatabase', 'testCollection');

const conversationState = new ConversationState(mongoDbStorage);
const userState = new UserState(mongoDbStorage);