SST Typescript 通过过滤检索 s3 存储桶对象名称和元数据密钥对

问题描述 投票:0回答:1

我是SST新手, 我尝试创建一个上传 API + Lambda 来上传文件并设置元数据,它成功了。 现在我正在尝试创建一个 API + Lambda 来检索文件列表。我能够检索完整的文件列表。但是,当我尝试根据元数据 createBy = USERNAME 过滤结果时 我无法做到这一点,任何指导将不胜感激。

import { GetObjectOutput } from "aws-sdk/clients/s3";
import * as AWS from 'aws-sdk';

export async function main(): Promise<any> {
  const s3 = new AWS.S3();

  const params = {
    Bucket: 'uni-artifacts', 
  };

  try {
    console.log("Listing objects in bucket:", params.Bucket);
    const data = await s3.listObjectsV2(params).promise();

    if (!data.Contents) {
      return {
        statusCode: 200,
        body: JSON.stringify({ message: "No files found in the bucket" }),
      };
    }

    console.log("Number of objects found:", data.Contents.length);

    const files = data.Contents.map(async (obj) => {
      try {
        const metadata = await getMetadata(s3, obj.Key!, () => {});
        return {
          Key: obj.Key,
          Metadata: metadata,
        };
      } catch (error) {
        console.error("Error getting metadata for", obj.Key, error);
        return { Key: obj.Key }; // Example handling, adjust based on needs
      }
    });

    // Wait for all promises to settle (including potential rejections)
    const resolvedFiles = await Promise.allSettled(files);

    // Filter and handle successful and rejected results
    const successfulFiles = resolvedFiles.filter((result) => result.status === "fulfilled")
      .map((result) => result); // No need to access value here

    const failedFiles = resolvedFiles.filter((result) => result.status === "rejected")
      .map((result) => {
        // Handle potential undefined data.Contents
        if (data?.Contents) {
          const failedFile = data.Contents.find(obj => obj.Key === (result as PromiseRejectedResult).reason?.Key); // Type cast to access reason on rejected result
          return failedFile ? { Key: failedFile.Key, Error: (result as PromiseRejectedResult).reason?.message } : undefined;
        } else {
          // Handle case where data.Contents is undefined (e.g., error during listObjectsV2)
          return { Error: "Error listing objects in bucket" }; // Example error message, adjust as needed
        }
      });

    const responseBody = {
      statusCode: 200,
      body: JSON.stringify({
        successfulFiles,
        failedFiles: failedFiles.filter(file => file), // Filter out undefined entries in failedFiles
      }),
    };

    return responseBody;
  } catch (error) {
    console.error("Error retrieving files:", error);
    return {
      statusCode: 500,
      body: JSON.stringify({ message: "Error retrieving files" }),
    };
  }
}

function getMetadata(s3: AWS.S3, key: string, callback: (error: Error | undefined, metadata?: GetObjectOutput["Metadata"]) => void) {
  const params = {
    Bucket: 'uni-artifacts', // Replace with your bucket name
    Key: key,
  };

  s3.headObject(params, (err, data) => {
    if (err) {
      console.error("Error getting metadata for", key, err);
      return callback(err);
    }

    console.log("Got metadata for:", key);
    callback(undefined, data.Metadata);
  });
}


我尝试创建一个数组列表来存储过滤后的结果。我觉得我的逻辑是错误的。

typescript amazon-s3 aws-lambda serverless sst
1个回答
0
投票
    import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
import * as AWS from 'aws-sdk';

interface S3ObjectMetadata {
  createdBy?: string; // Optional createdBy property
  creationDate?: string; // Optional creationDate property
}

export async function main(event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> {
  const s3 = new AWS.S3();

  // Parse the username parameter from the request URL
  const username = event.queryStringParameters?.username;
  console.log("Retrieved Username: " + username);

  const params = {
    Bucket: 'uni-artifacts', 
  };

  try {
    console.log("Listing objects in bucket:", params.Bucket);
    const data = await s3.listObjectsV2(params).promise();

    if (!data.Contents) {
      return {
        statusCode: 200,
        body: JSON.stringify({ message: "No files found in the bucket" }),
      };
    }

    console.log("Number of objects found:", data.Contents.length);

    const files = data.Contents.map(async (obj) => {
      try {
        const metadata = await getMetadata(s3, obj.Key!);
        return {
          Key: obj.Key,
          Metadata: metadata,
        };
      } catch (error) {
        console.error("Error getting metadata for", obj.Key, error);
        return { Key: obj.Key }; 
      }
    });

    const resolvedFiles = await Promise.allSettled(files);

    const successfulFiles = resolvedFiles.filter((result) => result.status === "fulfilled")
      .map((result) => {
        // Check if the result is fulfilled and has a value
        if (result.status === "fulfilled" && result.value) {
          const { Key, Metadata } = result.value; // Destructure if value exists
            //extract createdBy from metadata
          const createdBy = Metadata && typeof Metadata === 'object' && 'createdby' in Metadata ? Metadata.createdby : undefined;
          
          return {
            Key,
            Metadata: {
              createdBy, 
            }
          };
        } else {
          // Handle unsuccessful results or cases where value is missing
          console.error("Unexpected result:", result); 
          return { Key: undefined, Metadata: {} }; //  empty object 
        }
      });

    // Filter files based on createdBy metadata matching the username
    const filteredFiles = username ?
      successfulFiles.filter(file => {
        const createdBy = file.Metadata?.createdBy || '';
        console.log(`Comparing username '${username}' with createdBy '${createdBy}'`);
        const isMatch = createdBy === username;
        console.log(`Comparison result: ${isMatch}`);
        return isMatch;
      }) :
      successfulFiles;

    console.log("Filtered files:", filteredFiles); 

    const responseBody = {
      statusCode: 200,
      body: JSON.stringify({
        files: filteredFiles,
      }),
    };

    return responseBody;
  } catch (error) {
    console.error("Error retrieving files:", error);
    return {
      statusCode: 500,
      body: JSON.stringify({ message: "Error retrieving files" }),
    };
  }
}

function getMetadata(s3: AWS.S3, key: string): Promise<S3ObjectMetadata | undefined> {
  const params = {
    Bucket: 'uni-artifacts', 
    Key: key,
  };

  return new Promise((resolve, reject) => {
    s3.headObject(params, (err, data) => {
      if (err) {
        console.error("Error getting metadata for", key, err);
        reject(err);
      } else {
        const metadata = data.Metadata;
        console.log("Retrieved metadata for " + key, metadata);
        resolve(metadata);
      }
    });
  });
}
© www.soinside.com 2019 - 2024. All rights reserved.