Continuous Integration and Continuous Deployment are now common software development practices. In the world of databases, this translates into needing on-demand, stateful, ephemeral environments.
Provisioning a stateless environment is not tied to any particular source of data. All that is needed is to run the code you want to test in your CI environment. This is the basis of most CI/CD tools and won’t be covered in this article.
The slightly harder part comes from the dependencies the application needs to be tested properly, which is often referred to as external services. Couchbase being one of them. There are different ways to get those, through Docker containers for instance, or hosted in your test infrastructure, or some external as a Service solution. It does not really matter as long as they are available while running your test. Good practices would be to use Environment Variables to refer to those instances.
Assuming these services are running, like a Couchbase Free Tier instance or a Docker container, the next step is to make sure that they are configured correctly, and seeded with the data needed for the test.
A while ago, I posted about using Couchbase Shell in GitHub actions. This will tell you the basics about using Couchbase Shell with GitHub Actions, but this can be applied to most CI/CD solutions as well. Today, I want to go further and show you some useful scripts to clone a cluster or elements of a cluster for your on demand environments.
Using Couchbase Shell to clone environments
When using Couchbase Shell, the first thing that comes to mind when wanting to do something is, is there a function for that? As of now we don’t have a function to clone something. Most of the available functions reflect our APIs capabilities and we have no cloning APIs today. But, we have the ability to write scripts, which means we can make our own!
The first thing that comes to mind when managing databases is often to recreate the structure and schemas. As Couchbase is Schemaless, this will only consist of the existing buckets, scopes, collections, and indexes in the source cluster. The first step is to export that structure so it can be reimported later. This function will list every bucket, then inner scopes and collections, and add them to an array. Then it will list all indexes and add them to the output JSON.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# Exports all buckets, scopes, collections and indexes # for the given cluster def 내보내기-클러스터-구조체 [ 출처: 문자열 # The cluster to export ] { mut 내보내기 = [] let 버킷 = 버킷 --클러스터 $출처 # List the buckets of the given cluster 에 대한 버킷 in $버킷 { mut scope_structs = [] let 범위 = 범위 --클러스터 $출처 --버킷 $버킷.이름 에 대한 범위 in $범위 { let 컬렉션 = (컬렉션 --클러스터 $출처 --버킷 $버킷.이름 --범위 $범위.범위 | 거부 -i 클러스터) $scope_structs ++= [{ 범위: $범위.범위, 컬렉션: $컬렉션 }] } # Merge the scopes with the bucket object and add it to the export array let buc = ( $버킷 | 병합 {범위: $범위_structs } ) $내보내기 ++= [ $buc ] } let 인덱스 = 쿼리 인덱스 --정의 --비활성화-컨텍스트 --클러스터 $출처 let 출력 = { 버킷: $내보내기, 인덱스: $인덱스 } 반환 $출력 } |
This works because under the hood, Couchbase Shell is using Nushell, a new type of shell that is portable (meaning it works the same way on Linux, Windows, or OS X, which is great for CI/CD scripts having to support different OS), and that considers any structure data as a DataFrame, making the manipulation of JSON extremely easy.
To try it out, run cbsh, then source the file containing the function. For me it’s ci_scripts.nu. I have a cluster already configured in my cbsh config, called local
1 2 3 4 |
Laurent 도긴 에서 local in 여행-샘플.인벤토리._기본값 > 출처 ci-스크립트.nu Laurent 도긴 에서 local in 여행-샘플.인벤토리._기본값 > 내보내기-클러스터-구조체 local | 저장 local-클러스터-내보내기.json |
Now if you open local-cluster-export.json, you will get the structure of your cluster:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
{ "buckets": [ { "클러스터": "local", "name": "travel-sample", "type": "couchbase", "replicas": 0, "min_durability_level": "none", "ram_quota": 209715200, "flush_enabled": false, "cloud": false, "max_expiry": 0, "범위": [ { "범위": "인벤토리", "컬렉션": [ { "컬렉션": "공항", "max_expiry": "inherited" }, { "컬렉션": "항공사", "max_expiry": "inherited" }, { "컬렉션": "경로", "max_expiry": "inherited" }, { "컬렉션": "랜드마크", "max_expiry": "inherited" }, { "컬렉션": "호텔", "max_expiry": "inherited" } ] }, { "범위": "tenant_agent_00", "컬렉션": [ { "컬렉션": "users", "max_expiry": "inherited" }, { "컬렉션": "bookings", "max_expiry": "inherited" } ] }, { "범위": "tenant_agent_01", "컬렉션": [ { "컬렉션": "users", "max_expiry": "inherited" }, { "컬렉션": "bookings", "max_expiry": "inherited" } ] }, { "범위": "tenant_agent_02", "컬렉션": [ { "컬렉션": "users", "max_expiry": "inherited" }, { "컬렉션": "bookings", "max_expiry": "inherited" } ] }, { "범위": "tenant_agent_03", "컬렉션": [ { "컬렉션": "users", "max_expiry": "inherited" }, { "컬렉션": "bookings", "max_expiry": "inherited" } ] }, { "범위": "tenant_agent_04", "컬렉션": [ { "컬렉션": "users", "max_expiry": "inherited" }, { "컬렉션": "bookings", "max_expiry": "inherited" } ] }, { "범위": "_default", "컬렉션": [ { "컬렉션": "_default", "max_expiry": "inherited" } ] }, { "범위": "_system", "컬렉션": [ { "컬렉션": "_query", "max_expiry": "" }, { "컬렉션": "_mobile", "max_expiry": "" } ] } ] } ], "인덱스": [ { "bucket": "travel-sample", "범위": "_system", "컬렉션": "_query", "name": "#primary", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE PRIMARY INDEX `#primary` ON `travel-sample`.`_system`.`_query`", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "_default", "컬렉션": "_default", "name": "def_airportname", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_airportname` ON `travel-sample`(`airportname`) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "_default", "컬렉션": "_default", "name": "def_city", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_city` ON `travel-sample`(`city`) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "_default", "컬렉션": "_default", "name": "def_faa", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_faa` ON `travel-sample`(`faa`) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "_default", "컬렉션": "_default", "name": "def_icao", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_icao` ON `travel-sample`(`icao`) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "항공사", "name": "def_inventory_airline_primary", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE PRIMARY INDEX `def_inventory_airline_primary` ON `travel-sample`.`inventory`.`airline` WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "공항", "name": "def_inventory_airport_airportname", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_inventory_airport_airportname` ON `travel-sample`.`inventory`.`airport`(`airportname`) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "공항", "name": "def_inventory_airport_city", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_inventory_airport_city` ON `travel-sample`.`inventory`.`airport`(`city`) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "공항", "name": "def_inventory_airport_faa", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_inventory_airport_faa` ON `travel-sample`.`inventory`.`airport`(`faa`) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "공항", "name": "def_inventory_airport_primary", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE PRIMARY INDEX `def_inventory_airport_primary` ON `travel-sample`.`inventory`.`airport` WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "호텔", "name": "def_inventory_hotel_city", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_inventory_hotel_city` ON `travel-sample`.`inventory`.`hotel`(`city`) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "호텔", "name": "def_inventory_hotel_primary", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE PRIMARY INDEX `def_inventory_hotel_primary` ON `travel-sample`.`inventory`.`hotel` WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "랜드마크", "name": "def_inventory_landmark_city", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_inventory_landmark_city` ON `travel-sample`.`inventory`.`landmark`(`city`) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "랜드마크", "name": "def_inventory_landmark_primary", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE PRIMARY INDEX `def_inventory_landmark_primary` ON `travel-sample`.`inventory`.`landmark` WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "경로", "name": "def_inventory_route_primary", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE PRIMARY INDEX `def_inventory_route_primary` ON `travel-sample`.`inventory`.`route` WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "경로", "name": "def_inventory_route_route_src_dst_day", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_inventory_route_route_src_dst_day` ON `travel-sample`.`inventory`.`route`(`sourceairport`,`destinationairport`,(distinct (array (`v`.`day`) for `v` in `schedule` end))) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "경로", "name": "def_inventory_route_schedule_utc", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_inventory_route_schedule_utc` ON `travel-sample`.`inventory`.`route`(array (`s`.`utc`) for `s` in `schedule` end) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "인벤토리", "컬렉션": "경로", "name": "def_inventory_route_sourceairport", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_inventory_route_sourceairport` ON `travel-sample`.`inventory`.`route`(`sourceairport`) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "_default", "컬렉션": "_default", "name": "def_name_type", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_name_type` ON `travel-sample`(`name`) WHERE (`_type` = \"User\") WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "_default", "컬렉션": "_default", "name": "def_primary", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE PRIMARY INDEX `def_primary` ON `travel-sample` WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "_default", "컬렉션": "_default", "name": "def_route_src_dst_day", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_route_src_dst_day` ON `travel-sample`(`sourceairport`,`destinationairport`,(distinct (array (`v`.`day`) for `v` in `schedule` end))) WHERE (`type` = \"route\") WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "_default", "컬렉션": "_default", "name": "def_schedule_utc", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_schedule_utc` ON `travel-sample`(array (`s`.`utc`) for `s` in `schedule` end) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "_default", "컬렉션": "_default", "name": "def_sourceairport", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_sourceairport` ON `travel-sample`(`sourceairport`) WITH { \"defer_build\":true }", "클러스터": "local" }, { "bucket": "travel-sample", "범위": "_default", "컬렉션": "_default", "name": "def_type", "status": "Ready", "storage_mode": "memory_optimized", "replicas": 0, "definition": "CREATE INDEX `def_type` ON `travel-sample`(`type`) WITH { \"defer_build\":true }", "클러스터": "local" } ] } |
I have deleted that bucket for the purpose of this test, to reimport it later: buckets drop travel-sample.
The next logical step is to have a function that takes this file as input and recreate the complete structure in another cluster:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# Import all buckets, scopes and collections structure # in the given cluster def 가져오기-클러스터-구조체 [ 목적지: 문자열 # The cluster to import ] { let 구조 = $in # Assigning the piped structure to a variable let 버킷 = $구조.버킷 에 대한 버킷 in $버킷 { $버킷 | _create-버킷-정의 $목적지 에 대한 범위 in ($버킷.범위 | 어디 not ( $it.범위 | str 시작-와 함께 "_" ) ) { 인쇄 $"Create scope ($destination)_($bucket.name)_($scope.scope)" 범위 create --클러스터 $목적지 --버킷 $버킷.이름 $범위.범위 에 대한 col in $범위.컬렉션 { 인쇄 $"Create collection ($destination)_($bucket.name)_($scope.scope)_($col.collection)" 컬렉션 create --클러스터 $목적지 --버킷 $버킷.이름 --범위 $범위.범위 $col.컬렉션 } } } let 인덱스 = $구조.인덱스 $인덱스 | _create-인덱스 $목적지 # Nushell allows you to use other functions you created } def _create-인덱스 [ 목적지: 문자열 # the cluster where to create indexes ] { let 인덱스 = $in 에 대한 색인 in $인덱스 { 인쇄 $"Recreating index ($index.name) on cluster ($destination) with: " 인쇄 $색인.정의 쿼리 $색인.정의 --비활성화-컨텍스트 --클러스터 $목적지 } } |
Now to run that function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
Laurent 도긴 에서 local in 여행-샘플.인벤토리._기본값 > 열기 local-클러스터-내보내기.json | 가져오기-클러스터-구조체 아카펠라 Laurent 도긴 에서 local in 여행-샘플.인벤토리._기본값 > 열기 local-클러스터-내보내기.json | 가져오기-클러스터-구조체 local 만들기 버킷 local_travel-샘플 와 함께 200 할당량, 유형 카우치베이스, 0 복제본, 없음 내구성, 0 만료 만들기 범위 local_travel-sample_inventory 만들기 컬렉션 local_travel-sample_inventory_airport 만들기 컬렉션 local_travel-sample_inventory_airline 만들기 컬렉션 local_travel-sample_inventory_route 만들기 컬렉션 local_travel-sample_inventory_landmark 만들기 컬렉션 local_travel-sample_inventory_hotel 만들기 범위 local_travel-sample_tenant_agent_00 만들기 컬렉션 local_travel-sample_tenant_agent_00_users 만들기 컬렉션 local_travel-sample_tenant_agent_00_bookings 만들기 범위 local_travel-sample_tenant_agent_01 만들기 컬렉션 local_travel-sample_tenant_agent_01_users 만들기 컬렉션 local_travel-sample_tenant_agent_01_bookings 만들기 범위 local_travel-sample_tenant_agent_02 만들기 컬렉션 local_travel-sample_tenant_agent_02_users 만들기 컬렉션 local_travel-sample_tenant_agent_02_bookings 만들기 범위 local_travel-sample_tenant_agent_03 만들기 컬렉션 local_travel-sample_tenant_agent_03_users 만들기 컬렉션 local_travel-sample_tenant_agent_03_bookings 만들기 범위 local_travel-sample_tenant_agent_04 만들기 컬렉션 local_travel-sample_tenant_agent_04_users 만들기 컬렉션 local_travel-sample_tenant_agent_04_bookings 재창조 색인 #primary on cluster local with: 만들기 기본 INDEX `#primary` ON `travel-sample`.`_system`.`_query` 재창조 색인 def_공항명 on 클러스터 local 와 함께: 만들기 INDEX `def_공항명` 켜기 `여행-샘플`(`공항명`) WITH { "defer_build":true } 재창조 색인 def_city on 클러스터 local 와 함께: 만들기 INDEX `def_city` 켜기 `여행-샘플`(`도시`) WITH { "defer_build":true } 재창조 색인 def_faa on 클러스터 local 와 함께: 만들기 INDEX `def_faa` 켜기 `여행-샘플`(`faa`) WITH { "defer_build":true } 재창조 색인 def_icao on 클러스터 local 와 함께: 만들기 INDEX `def_icao` 켜기 `여행-샘플`(`icao`) WITH { "defer_build":true } 재창조 색인 def_inventory_airline_primary on 클러스터 local 와 함께: 만들기 기본 INDEX `def_inventory_airline_primary` 켜기 `여행-샘플`.`인벤토리`.`항공사` WITH { "defer_build":true } 재창조 색인 def_inventory_airport_airportname on 클러스터 local 와 함께: 만들기 INDEX `def_inventory_airport_airportname` 켜기 `여행-샘플`.`인벤토리`.`공항`(`공항명`) WITH { "defer_build":true }재창조 색인 def_inventory_airport_city on 클러스터 local 와 함께: 만들기 INDEX `def_inventory_airport_city` 켜기 `여행-샘플`.`인벤토리`.`공항`(`도시`) WITH { "defer_build":true } 재창조 색인 def_inventory_airport_faa on 클러스터 local 와 함께: 만들기 INDEX `def_inventory_airport_faa` 켜기 `여행-샘플`.`인벤토리`.`공항`(`faa`) WITH { "defer_build":true } 재창조 색인 def_inventory_airport_primary on 클러스터 local 와 함께: 만들기 기본 INDEX `def_inventory_airport_primary` 켜기 `여행-샘플`.`인벤토리`.`공항` WITH { "defer_build":true } 재창조 색인 def_inventory_hotel_city on 클러스터 local 와 함께: 만들기 INDEX `def_inventory_hotel_city` 켜기 `여행-샘플`.`인벤토리`.`호텔`(`도시`) WITH { "defer_build":true } 재창조 색인 def_inventory_hotel_primary on 클러스터 local 와 함께: 만들기 기본 INDEX `def_inventory_hotel_primary` 켜기 `여행-샘플`.`인벤토리`.`호텔` WITH { "defer_build":true } 재창조 색인 def_inventory_landmark_city on 클러스터 local 와 함께: 만들기 INDEX `def_inventory_landmark_city` 켜기 `여행-샘플`.`인벤토리`.`랜드마크`(`도시`) WITH { "defer_build":true } 재창조 색인 def_inventory_landmark_primary on 클러스터 local 와 함께: 만들기 기본 INDEX `def_inventory_landmark_primary` 켜기 `여행-샘플`.`인벤토리`.`랜드마크` WITH { "defer_build":true } 재창조 색인 def_inventory_route_primary on 클러스터 local 와 함께: 만들기 기본 INDEX `def_inventory_route_primary` 켜기 `여행-샘플`.`인벤토리`.`경로` WITH { "defer_build":true } 재창조 색인 def_inventory_route_route_src_dst_day on 클러스터 local 와 함께: 만들기 INDEX `def_inventory_route_route_src_dst_day` 켜기 `여행-샘플`.`인벤토리`.`경로`(`소스공항`,`목적지공항`,(distinct (배열 (`v`.`일`) 에 대한 `v` in `일정` 끝))) WITH { "defer_build":true } 재창조 색인 def_inventory_route_schedule_utc on 클러스터 local 와 함께: 만들기 INDEX `def_inventory_route_schedule_utc` 켜기 `여행-샘플`.`인벤토리`.`경로`(배열 (`s`.`UTC`) 에 대한 `s` in `일정` 끝) WITH { "defer_build":true } 재창조 색인 def_inventory_route_sourceairport on 클러스터 local 와 함께: 만들기 INDEX `def_inventory_route_sourceairport` 켜기 `여행-샘플`.`인벤토리`.`경로`(`소스공항`) WITH { "defer_build":true } 재창조 색인 def_name_type on 클러스터 local 와 함께: 만들기 INDEX `def_name_type` 켜기 `여행-샘플`(`이름`) 어디 (`_유형` = "사용자") WITH { "defer_build":true } 재창조 색인 def_primary on 클러스터 local 와 함께: 만들기 기본 INDEX `def_primary` 켜기 `여행-샘플` WITH { "defer_build":true } 재창조 색인 def_route_src_dst_day on 클러스터 local 와 함께: 만들기 INDEX `def_route_src_dst_day` 켜기 `여행-샘플`(`소스공항`,`목적지공항`,(distinct (배열 (`v`.`일`) 에 대한 `v` in `일정` 끝))) 어디 (`유형` = "경로") WITH { "defer_build":true } 재창조 색인 def_schedule_utc on 클러스터 local 와 함께: 만들기 INDEX `def_schedule_utc` 켜기 `여행-샘플`(배열 (`s`.`UTC`) 에 대한 `s` in `일정` 끝) WITH { "defer_build":true } 재창조 색인 def_sourceairport on 클러스터 local 와 함께: 만들기 INDEX `def_sourceairport` 켜기 `여행-샘플`(`소스공항`) WITH { "defer_build":true } 재창조 색인 def_type on 클러스터 local 와 함께: 만들기 INDEX `def_type` 켜기 `여행-샘플`(`유형`) WITH { "defer_build":true } |
And there you have it, functions that allow you to export and import the data structure from one cluster to another. While this is a good starting point, there are still questions about how to reimport data, or about granularity. Also, you may not want to export and import a complete cluster.
Filtering buckets to import is fairly easy as Nushell allows you to filter dataframes:
1 2 |
Laurent 도긴 에서 local in 여행-샘플.인벤토리._기본값 > 열기 local-클러스터-내보내기.json | { 버킷: ( $in.버킷 | 어디 이름 == 'travel-sample'), 인덱스 :( $in.인덱스 | 어디 버킷 == 'travel-sample') } |
This will recreate a JSON object containing only a bucket named 여행 샘플 and indexes for this bucket.
From there you should be all set to manage basic cluster structure. What about the data? There are different ways you can import data with cbsh, as it covers most key/value operations as well as any INSERT/UPSERT queries. And then we have the 문서 가져오기 명령. Its usage is fairly straightforward, all you need is a list of rows with an identified id field. This can be anything that can be turned into a dataframe for Nushell (XML, CSV, TSV, Parquet, and more). And of course, it can be a JSON file from a Couchbase SQL++ query. This is an example that will save a query result to a file and import that file back to a collection:
1 2 3 4 5 6 7 8 |
# Save file content to filename let 파일 이름 = $"temp_($src_bucket)_($src_scope)_($src_collection).json" let 쿼리 = "SELECT meta().id as meta_id, meta().expiration as expiration, c.* FROM `" + $src_bucket + "`." + $src_scope + "." + $src_collection + " c" 쿼리 --비활성화-컨텍스트 --클러스터 $p.src $쿼리 | 저장 -f $파일 이름 # Import the file content and print the results 인쇄 $"Import collection content from ($src)_($src_bucket)_($src_scope)_($src_collection) to ($dest)_($dest_bucket)_($dest_scope)_($dest_collection)" 인쇄 ( doc 가져오기 --버킷 $p.dest_bucket --범위 $p.dest_scope --컬렉션 $p.dest_collection --클러스터 $p.dest --id-column 메타_id $파일 이름 ) |
That’s one particular example but the whole point of using scripting language is to make them your own. You will find a more complete example in this GitHub Gist. It has support for environment variables for source and destination and you can decide to either clone all buckets of a cluster, a specific bucket, scope, or collection.
Don’t hesitate to drop us a comment here or on 불화, we are always looking for suggestions to improve the global Couchbase experience.