CouchDB复制以便将我的数据库克隆到一个新示例中

3b6akqbq  于 2023-09-28  发布在  CouchDB
关注(0)|答案(1)|浏览(190)

我正在将我的DB复制到另一个CouchDB示例中。为了测试它,我创建了两个Docker镜像,一个包含一些示例数据,另一个作为空示例。包含测试数据的DB在localhost:5984上运行,而我想将数据复制到的目标示例在localhost:5985上可用。
下面是我的代码:

const replicateTest = async () => {
  try {
    const { data } = await axios.post(
      "http://localhost:5984/_replicate",
      {
        source: `http://admin:admin@localhost:5984/test_1`,
        target: `http://admin:admin@localhost:5985/test_1`,
        create_target: true,
      },
      {
        headers: {
          "Content-Type": "application/json",
          Accept: "application/json",
        },
      }
    );

    console.log(data);
  } catch (err) {
    console.log(err);
  }
};

这是我得到的错误响应:{ error: 'invalid_json', reason: '{1,invalid_json}' }
以下是我试图进行的测试列表:
1.为了确保我的服务器正确运行,我使用下面的代码查询它们,该代码成功运行。它确认不存在连接问题:

const { data } = await axios.get(
    "http://admin:admin@localhost:5984/_all_dbs"
);
  • 我已经修改了很多次帖子请求,得到了同样的结果。以下是我尝试的一些变化:
  • 我尝试将完整路径传递给post请求,例如http://admin:admin@localhost:5984/_replicate
  • 传递一个curl请求,而不是我的axios请求。
  • 我使用IP 127.0.0.1而不是localhost进行测试。
  • 我参考了CouchDB的文档,但没有太大的成功。
  • 使用此语法时:
const { data } = await axios.post(
      "http://localhost:5984/_replicate",
      {
        source: `http://admin:admin@localhost:5984/test_1`,
        target: {
          url: "http://localhost:5985/test_1",
          auth: {
            basic: {
              username: "admin",
              password: "admin",
            },
          },
        },
        create_target: true,
      },
      {
        headers: {
          "Content-Type": "application/json",
          Accept: "application/json",
        },
      }
    );

我收到这个错误:

data: {
      error: 'replication_auth_error',
      reason: '{session_request_failed,"http://localhost:5985/_session","admin",\n' +
        '                        {conn_failed,{error,econnrefused}}}'
    }

我正在添加我的docker-compose.yaml文件:

version: "3"

services:
  couchdb1:
    image: couchdb:latest
    container_name: my-couchdb1
    ports:
      - "5984:5984"
    environment:
      COUCHDB_USER: admin
      COUCHDB_PASSWORD: admin
    volumes:
      - ./data1:/opt/couchdb/data

  couchdb2:
    image: couchdb:latest
    container_name: my-couchdb2
    ports:
      - "5985:5984"
    environment:
      COUCHDB_USER: admin
      COUCHDB_PASSWORD: admin
    volumes:
      - ./data2:/opt/couchdb/data
mw3dktmi

mw3dktmi1#

我仍在努力解决CouchDb的_replicate方法的问题,但是,我已经设法创建了一个临时解决方案,虽然不理想,但可以完成工作。这种方法涉及一个脚本,该脚本将每个数据库从源复制到目标,然后处理每个文档。
我使用lodashnanoprocess作为此过程的依赖项。
请看下面的脚本:

const sourceUrl = argv[2] ?? "http://admin:admin@localhost:5984/";
const targetUrl = argv[3] ?? "http://admin:admin@localhost:5985/";

const sourceDb = nano(sourceUrl);
const targetDb = nano(targetUrl);

const databasesReplicate = async () => {
  try {
    const allSourceDbs = await sourceDb.db.list();

    allSourceDbs.map(async (dbName) => {
      const isDbExistsResponse = await isDbExists(dbName);
      await createDb({ db: isDbExistsResponse, dbName });
      const docsData = await getAllDocs(dbName);

      const targetDbScope = targetDb.use(dbName);

      await Promise.allSettled(
        docsData.map(async (docData) => {
          if (docData.doc) {
            await insertDocument(docData.doc, targetDbScope);
          }
        })
      );
    });
  } catch (err) {
    console.log(err);
    throw err;
  }
};

const isDbExists = async (dbName: string) => {
  return await targetDb.db.get(dbName).catch((err) => {
    if (err.statusCode === 404) {
      return null;
    }

    throw err;
  });
};

const createDb = async ({ db, dbName }: CreateDbInterface) => {
  if (!db) {
    await targetDb.db.create(dbName);
    console.info(`database '${dbName}' created in the target CouchDB.`);
  }

  console.log(dbName)
};

const getAllDocs = async (dbName: string) =>
  (await sourceDb.use(dbName).list({ include_docs: true })).rows;

const insertDocument = async (doc: Document, db: DocumentScope<unknown>) => {
  const selector = {
    selector: {
      _id: { $eq: doc._id },
    },
    limit: 1,
  };

  const existingData = await findOneDocByFilter({ db, selector });
  const docToInsert = omit(doc, "_rev");

  return existingData
    ? await db.insert({ ...docToInsert, _rev: existingData._rev })
    : await db.insert(docToInsert);
};

const findOneDocByFilter = async ({ db, selector }: FindByInterface) => {
  try {
    const { docs } = await db.find(selector);
    return docs.length ? docs[0] : null;
  } catch (err) {
    throw err;
  }
};

相关问题