Skip to content

Instantly share code, notes, and snippets.

@dylankelly
Created April 28, 2025 06:46
Show Gist options
  • Select an option

  • Save dylankelly/462c8db7d3d47756f023a4fe2970db25 to your computer and use it in GitHub Desktop.

Select an option

Save dylankelly/462c8db7d3d47756f023a4fe2970db25 to your computer and use it in GitHub Desktop.
import dotenv from 'dotenv';
// Load environment variables
dotenv.config();
const {
SOURCE_APP_SEARCH_URL,
SOURCE_APP_SEARCH_API_KEY,
DEST_APP_SEARCH_URL,
DEST_APP_SEARCH_API_KEY,
SOURCE_ENGINE_NAME,
DEST_ENGINE_NAME
} = process.env;
// Validate env vars
if (!SOURCE_APP_SEARCH_URL || !SOURCE_APP_SEARCH_API_KEY ||
!DEST_APP_SEARCH_URL || !DEST_APP_SEARCH_API_KEY ||
!SOURCE_ENGINE_NAME || !DEST_ENGINE_NAME) {
console.error('❌ Missing required environment variables.');
process.exit(1);
}
const BATCH_SIZE = 100; // App Search allows up to 100 docs per batch
// Function to fetch documents from the source engine
async function fetchDocumentsFromSource(page) {
const url = `${SOURCE_APP_SEARCH_URL}/api/as/v1/engines/${SOURCE_ENGINE_NAME}/search`;
const body = {
query: '',
page: {
size: BATCH_SIZE,
current: page
}
};
console.log(`⏳ Fetching documents from source engine, page ${page}...`);
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${SOURCE_APP_SEARCH_API_KEY}`
},
body: JSON.stringify(body)
});
if (!response.ok) {
throw new Error(`Error fetching documents from source engine: ${response.statusText}`);
}
const data = await response.json();
console.log(`πŸ“„ Fetched ${data.results.length} documents from source engine (Page ${page})`);
return data;
}
// Function to index an individual document into the destination engine
async function indexDocumentToDest(doc) {
const url = `${DEST_APP_SEARCH_URL}/api/as/v1/engines/${DEST_ENGINE_NAME}/documents`;
console.log(`πŸ“€ Indexing document with ID: ${doc.id.raw} to destination engine...`);
delete doc._meta
delete doc.id
const indexDoc = Object.fromEntries(
Object.entries(doc).map(([key, value]) => [key, value.raw])
);
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${DEST_APP_SEARCH_API_KEY}`
},
body: JSON.stringify(indexDoc) // Send the document as is
});
if (!response.ok) {
throw new Error(`Error indexing document to destination engine: ${response.statusText}`);
}
const responseData = await response.json();
console.log(`βœ… Successfully indexed document with ID: ${responseData[0].id}`);
return responseData;
}
async function copyAppSearchEngine() {
let currentPage = 1;
let totalCopied = 0;
let done = false;
while (!done) {
try {
// Fetch documents from the source engine
const searchResponse = await fetchDocumentsFromSource(currentPage);
if (searchResponse.results.length === 0) {
console.log('βœ… No more documents to copy.');
done = true;
break;
}
// For each document, index it individually into the destination engine
for (const doc of searchResponse.results) {
console.log(`πŸ” Processing document with ID: ${doc.id.raw}`);
await indexDocumentToDest(doc);
totalCopied++;
}
console.log(`πŸ“„ Copied ${totalCopied} documents so far...`);
currentPage++;
} catch (error) {
console.error('❌ Error during copy:', error.message);
process.exit(1);
}
}
console.log('βœ… Finished copying all documents!');
}
copyAppSearchEngine();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment