【发布时间】:2021-02-21 21:56:47
【问题描述】:
我们刚刚使用follower changeover 方法升级了我们的Heroku postgres 数据库。我们有超过 50 个数据剪辑附加到旧数据库,现在我们需要将它们移动到新数据库。但是,一个一个地做会花费很多时间。
是否有一种编程方式来更新数据剪辑附加到的数据库,也许使用 CLI 工具?
【问题讨论】:
我们刚刚使用follower changeover 方法升级了我们的Heroku postgres 数据库。我们有超过 50 个数据剪辑附加到旧数据库,现在我们需要将它们移动到新数据库。但是,一个一个地做会花费很多时间。
是否有一种编程方式来更新数据剪辑附加到的数据库,也许使用 CLI 工具?
【问题讨论】:
至少在取消配置旧数据库后,您现在可以(截至 2016 年 3 月)将它们重新附加到另一个数据库:
转到https://dataclips.heroku.com/clips/recoverable。它将显示您的旧数据库和一组“孤立”数据剪辑,您可以选择将它们转移到另一个数据库(在我的情况下,是从转换中提升的追随者)。
请注意,这只影响您创建的数据剪辑,它不影响您的团队成员之一创建并且您只能访问的数据剪辑。所以他们也必须经历这个过程。
开发中心官方文章:https://devcenter.heroku.com/articles/dataclips#dataclip-recovery
【讨论】:
感谢 Heroku CSRF 措施,以编程方式更新数据剪辑比您想象的要困难得多。你需要接受它并开始手动点击按钮,或者请求他们的支持团队为你做这件事,这同样困难。
官方不支持以编程方式移动数据剪辑。话虽如此,您可以针对他们的 HTTP API 编写脚本。
基本 URL 是 https://dataclips.heroku.com/api/v1/。共有三个相关端点:
/clips
/heroku_resources
/clips/:slug/move
找到你要移动的剪辑的slug,找到新数据库的资源id,并发布到移动剪辑端点:
POST /api/v1/clips/fjhwieufysdufnjqqueyuiewsr/move
Content-Type: application/json
{"heroku_resource_id":"resource123456789@heroku.com"}
【讨论】:
我有 300 多个数据剪辑要移动。我使用以下技术来更新它们(本质上是对数据剪辑 API 进行逆向工程)。
https://dataclips.heroku.com/api/v1/clips) 格式返回所有数据剪辑的网络调用。获取此响应并提取所有 dataclip slug。https://dataclips.heroku.com/api/v1/clips/:slug/move)。右键单击,复制为 cURL。这是获取所有正确参数的最简单方法,因为 API 使用 cookie 进行身份验证。编写一个循环遍历每个 dataclip slug 的脚本,然后执行 curl。在 Ruby 中,这看起来像:
slugs = <paste ids here>.split("\n")
slugs.each do |slug|
command = %Q(curl -v 'https://dataclips.heroku.com/api/v1/clips/#{slug}/move' -H 'Cookie: ...' --data '{"heroku_resource_id":"resource1234567@heroku.com"}')
puts command
system(command)
end
【讨论】:
您可以联系 Heroku 支持,他们会为您将数据剪辑批量传输到您的新数据库。
【讨论】:
我终于找到了一个解决方案,可以使用 javascript 控制台和一些抓取技术批量处理我的 Dataclips。我需要它来检索每个数据剪辑。但它猜测它可以这样更新:
// Go to the dataclip listing (https://data.heroku.com/dataclips).
// Then execute this script in your console.
// Be careful, this will focus a new window every 4 seconds, preventing
// you from working 4 seconds times the number of dataclips you have.
// Retrieve urls and titles
let dataclips = Array.
from(document.querySelectorAll('.rt-td:first-child a')).
map(el => ({ url: el.href, title: el.innerText }))
/**
* Allows waiting for a given timeout before execution.
* @param {number} seconds
*/
const timeout = function(seconds) {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, seconds);
})
}
/**
* Here are all the changes you want to apply to every single
* dataclip.
* @param {object} window
*/
const applyChanges = function(window) {
}
// With a fast connection, 4 seconds is OK. Dial it down if you
// have errors.
const expectedLoadTime = 4000 // ms
// This is the main loop, windows are opened one by one to ensure focus and a
// correct loading time.
for (const dataclip of dataclips) {
// This opens another window from the script, having access to its DOM.
// See https://github.com/buonomo/kazoo for a funnier example usage!
// And don't be shy to star and share :D
const externWindow = window.open(dataclip.url)
// A hack to wait for loading, this could be improved for sure.
await timeout(expectedLoadTime)
applyChanges(externWindow)
externWindow.close()
}
您仍然需要自己实现applyChanges,我承认这有点乏味,而且我没有时间知道(如果有,请分享!)。但至少它可以在一个函数中对所有数据剪辑完成。
有关此脚本的示例用法,您可以查看the gist I made to scrape every dataclips and related errors。
【讨论】: