การอัปเดตแบบเรียลไทม์

ส่วนนี้จะอธิบายวิธีส่งการอัปเดตรายการพื้นที่โฆษณาของคุณที่ขึ้นอยู่กับเวลาไปยัง Google API การอัปเดตแบบเรียลไทม์ช่วยให้คุณพุชการอัปเดตและลบเอนทิตีในแซนด์บ็อกซ์หรือพื้นที่โฆษณาเวอร์ชันที่ใช้งานจริงได้แบบเกือบเรียลไทม์

ฟังก์ชันการทำงานนี้มีไว้เพื่อการอัปเดตที่คุณคาดการณ์ไม่ได้เป็นหลัก เช่น การปิดในกรณีฉุกเฉิน การนำรายการออกจากเมนู หรืออัปเดตราคารายการในเมนู ซึ่งต้องแสดงใน UI ของ Google อย่างรวดเร็ว หากการเปลี่ยนแปลงไม่จำเป็นต้องมีผลทันที คุณใช้การนำเข้าแบบกลุ่มแทนได้ การอัปเดตแบบเรียลไทม์ จะใช้เวลาไม่เกิน 5 นาที

ข้อกำหนดเบื้องต้น

สิ่งที่คุณต้องทำก่อนใช้งานการอัปเดตแบบเรียลไทม์มีดังนี้

  1. เปิดใช้ Maps Booking API แล้ว:
    • ใน GCP ให้ไปที่ API และบริการ > ไลบรารี
    • ค้นหา "Google Maps Booking API"
      ค้นหา Google Maps Booking API
    • ค้นหาอินสแตนซ์ของแซนด์บ็อกซ์ (“Google Maps Booking API (Dev)”) แล้วคลิกเปิดใช้
    • ค้นหาอินสแตนซ์เวอร์ชันที่ใช้งานจริง ("Google Maps Booking API") แล้วคลิกเปิดใช้
      เปิดใช้ Google Maps Booking API
  2. ระบบได้สร้างบัญชีบริการที่มีบทบาทผู้แก้ไขให้กับโปรเจ็กต์ GCP ดูรายละเอียดเพิ่มเติมได้ที่ การสร้างบัญชี
  3. ฟีดข้อมูลการผลิตหรือแซนด์บ็อกซ์จะโฮสต์และนำเข้า โปรดดูรายละเอียดเพิ่มเติมที่การส่งผ่านข้อมูลเป็นกลุ่ม
  4. สำหรับการตรวจสอบสิทธิ์ API เราขอแนะนำให้ติดตั้งไลบรารีของไคลเอ็นต์ Google ในภาษาที่คุณต้องการ ใช้ “https://www.googleapis.com/auth/mapsbooking” เป็นขอบเขต OAuth ตัวอย่างโค้ดที่แสดงด้านล่างใช้ไลบรารีเหล่านี้ ไม่เช่นนั้น คุณจะต้องจัดการการแลกเปลี่ยนโทเค็นด้วยตนเองตามที่อธิบายไว้ในการใช้ OAuth 2.0 เพื่อเข้าถึง Google API

ภาพรวม

API การอัปเดตแบบเรียลไทม์รองรับการดำเนินการ 2 ประเภท การดำเนินการแรกคือ Upsert สำหรับการอัปเดตเอนทิตีที่มีอยู่ การดำเนินการที่ 2 คือการลบเพื่อนำเอนทิตีออกจากพื้นที่โฆษณา การดำเนินการทั้ง 2 อย่างนี้จะใช้กับช่วงของเอนทิตีที่แสดงในเนื้อหาของคำขอ คุณอัปเดตเอนทิตีได้สูงสุด 1,000 รายการในการเรียก API 1 ครั้ง API จะยอมรับคําขอที่เข้ามาใหม่ทั้งหมด และจัดไว้ในคิวเพื่อประมวลผลต่อไป ดังนั้นคำขอ RTU จะได้รับการประมวลผลแบบไม่พร้อมกัน

API การอัปเดตแบบเรียลไทม์ทำงานใน 2 สภาพแวดล้อม ได้แก่ แซนด์บ็อกซ์และเวอร์ชันที่ใช้งานจริง สภาพแวดล้อมแซนด์บ็อกซ์ใช้สำหรับการทดสอบคำขอ API และสภาพแวดล้อมของเวอร์ชันที่ใช้งานจริงเพื่ออัปเดตเนื้อหาที่ผู้ใช้ปลายทางที่สั่งซื้อเห็นได้ ชื่อโฮสต์ของทั้ง 2 สภาพแวดล้อม

  • แซนด์บ็อกซ์ - partnerdev-mapsbooking.googleapis.com
  • เวอร์ชันที่ใช้งานจริง - mapsbooking.googleapis.com

ปลายทาง

API การอัปเดตแบบเรียลไทม์จะแสดงปลายทาง 2 แห่งเพื่อจัดการคำขอขาเข้าสำหรับการอัปเดตสินค้าคงคลัง ดังนี้

  • เหนือ - /v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
  • ลบ - /v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete

ดูพารามิเตอร์ PARTNER_ID ได้ในศูนย์การดําเนินการซึ่งแสดงเป็นรหัสพาร์ทเนอร์ในหน้าบัญชีและผู้ใช้ ดังที่แสดงในภาพหน้าจอด้านล่าง

รหัสพาร์ทเนอร์ในพอร์ทัลของพาร์ทเนอร์

ดูตัวอย่างจาก 10000001 ของ PARTNER_ID จากภาพหน้าจอด้านบน ซึ่ง URL ที่สมบูรณ์สำหรับการส่งคำขอ API ในแซนด์บ็อกซ์และเวอร์ชันที่ใช้งานจริงจะมีลักษณะเหมือนในตัวอย่างด้านล่าง

# Sandbox UPSERT
https://partnerdev-mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchPush
# Sandbox DELETE
https://partnerdev-mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchDelete
# Production UPSERT
https://mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchPush
# Production DELETE
https://mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchDelete

การอัปเดตเอนทิตี

หากต้องการอัปเดตเอนทิตีในสินค้าคงคลัง ให้ใช้ปลายทาง UPSERT และส่งคำขอ HTTP POST คำขอ POST แต่ละรายการต้องมีพารามิเตอร์ PARTNER_ID พร้อมด้วยเพย์โหลด JSON ที่มีข้อมูลที่มีโครงสร้างของเอนทิตีทุกประเภทที่แสดงในสคีมาพื้นที่โฆษณา

เพย์โหลดคำขอ Upsert

เนื้อหาของคำขอเป็นออบเจ็กต์ JSON ที่มีรายการระเบียน ระเบียนแต่ละรายการจะสอดคล้องกับเอนทิตีที่กำลังอัปเดต ซึ่งประกอบด้วยช่อง data_record ที่มีเปย์โหลดของเอนทิตีที่เข้ารหัสใน Base64 และ generation_timestamp ที่ระบุเวลาของการอัปเดตเอนทิตี

  {
    "records": [
      {
        "data_record":"BASE_64_ENCODED_ENTITY",
        "generation_timestamp":"UPDATE_TIMESTAMP"
      }
    ]
  }

ในเพย์โหลดข้างต้น ให้แทนที่

  • BASE_64_ENCODED_ENTITY: สตริง JSON ที่เข้ารหัส Base64 ของเอนทิตี JSON ของเอนทิตีที่ถอดรหัสควรมีโครงสร้างเหมือนกับในข้อกำหนดฟีด เช่น

    {"@type":"MenuSection","name":"My Updated Menu Section","menuId":{"@id":"10824","displayOrder":1},"@id":"853705"}
  • UPDATE_TIMESTAMP: อย่าลืมใส่การประทับเวลาเมื่อสร้างเอนทิตีในระบบแบ็กเอนด์ การประทับเวลานี้ใช้เพื่อให้แน่ใจว่าลำดับการอัปเดตสินค้าคงคลังถูกต้อง ถ้าไม่มีช่องนี้ ช่องจะถูกตั้งค่าเป็นเวลาที่ Google ได้รับคำขอ เมื่ออัปเดตเอนทิตีผ่านคำขอ batchPush ระบบจะใช้ช่อง generation_timestamp สำหรับการกำหนดเวอร์ชันเอนทิตี ดูรูปแบบค่าเวลาที่คาดไว้ในสคีมาสินค้าคงคลังแบบสัมพันธ์

คำขออัปเดตแบบเรียลไทม์ทุกครั้งต้องเป็นไปตามเงื่อนไขต่อไปนี้

  • ส่วนเนื้อหาเพย์โหลดต้องมีขนาดไม่เกิน 5 MB เราขอแนะนำให้คุณตัดช่องว่างออกเพื่อให้มีข้อมูลมากขึ้นคล้ายกับฟีดแบบกลุ่ม
  • คำขอ batchPush มีเอนทิตีได้สูงสุด 1,000 รายการ

ตัวอย่าง

ตัวอย่างที่ 1: การอัปเดตร้านอาหาร

สมมติว่าคุณต้องอัปเดตหมายเลขโทรศัพท์ของร้านอาหารอย่างเร่งด่วน การอัปเดตของคุณมี JSON สำหรับทั้งร้านอาหาร

ลองใช้ฟีดแบบกลุ่มที่มีลักษณะดังนี้

{
  "@type": "Restaurant",
  "@id": "restaurant12345",
  "name": "Some Restaurant",
  "url": "https://www.provider.com/somerestaurant",
  "telephone": "+16501234570",
  "streetAddress": "345 Spear St",
  "addressLocality": "San Francisco",
  "addressRegion": "CA",
  "postalCode": "94105",
  "addressCountry": "US",
  "latitude": 37.472842,
  "longitude": -122.217144
}
  

จากนั้นการอัปเดตแบบเรียลไทม์โดย HTTP POST จะเป็นดังนี้

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "Restaurant",
        "@id": "restaurant12345",
        "name": "Some Restaurant",
        "url": "https://www.provider.com/somerestaurant",
        "telephone": "+16501234570",
        "streetAddress": "345 Spear St",
        "addressLocality": "San Francisco",
        "addressRegion": "CA",
        "postalCode": "94105",
        "addressCountry": "US",
        "latitude": 37.472842,
        "longitude": -122.217144
      }
      "generation_timestamp": "2022-08-19T17:11:10.750Z"
    }
  ]
}
    

Base64

ตัวอย่างเดียวกับเพย์โหลดที่เข้ารหัส Base64

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "eyJAdHlwZSI6IlJlc3RhdXJhbnQiLCJAaWQiOiJyZXN0YXVyYW50MTIzNDUiLCJuYW1lIjoiU29tZSBSZXN0YXVyYW50IiwidXJsIjoiaHR0cHM6Ly93d3cucHJvdmlkZXIuY29tL3NvbWVyZXN0YXVyYW50IiwidGVsZXBob25lIjoiKzE2NTAxMjM0NTcwIiwic3RyZWV0QWRkcmVzcyI6IjM0NSBTcGVhciBTdCIsImFkZHJlc3NMb2NhbGl0eSI6IlNhbiBGcmFuY2lzY28iLCJhZGRyZXNzUmVnaW9uIjoiQ0EiLCJwb3N0YWxDb2RlIjoiOTQxMDUiLCJhZGRyZXNzQ291bnRyeSI6IlVTIiwibGF0aXR1ZGUiOjM3LjQ3Mjg0MiwibG9uZ2l0dWRlIjotMTIyLjIxNzE0NH0="
      "generation_timestamp": "2022-08-19T17:11:10.750Z"
    }
  ]
}
    

ตัวอย่างที่ 2: การอัปเดตร้านอาหารหลายร้าน

หากต้องการอัปเดตเอนทิตีร้านอาหาร 2 รายการในการเรียก API เดียว คำขอ HTTP POST จะเป็นดังนี้

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "Restaurant",
        "@id": "restaurant12345",
        "name": "Some Restaurant",
        "url": "https://www.provider.com/somerestaurant",
        "telephone": "+16501235555",
        "streetAddress": "345 Spear St",
        "addressLocality": "San Francisco",
        "addressRegion": "CA",
        "postalCode": "94105",
        "addressCountry": "US",
        "latitude": 37.472842,
        "longitude": -122.217144
      },
      "generation_timestamp": "2022-08-19T17:11:10.850Z"
    },
    {
      "data_record": {
        "@type": "Restaurant",
        "@id": "restaurant123",
        "name": "Some Other Restaurant",
        "url": "https://www.provider.com/someotherrestaurant",
        "telephone": "+16501231235",
        "streetAddress": "385 Spear St",
        "addressLocality": "San Mateo",
        "addressRegion": "CA",
        "postalCode": "94115",
        "addressCountry": "US"
      },
      "generation_timestamp": "2022-08-19T17:11:10.850Z"
    }
  ]
}
    

Base64

ตัวอย่างเดียวกับเพย์โหลดที่เข้ารหัส Base64

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "eyJAdHlwZSI6IlJlc3RhdXJhbnQiLCJAaWQiOiJyZXN0YXVyYW50MTIzNDUiLCJuYW1lIjoiU29tZSBSZXN0YXVyYW50IiwidXJsIjoiaHR0cHM6Ly93d3cucHJvdmlkZXIuY29tL3NvbWVyZXN0YXVyYW50IiwidGVsZXBob25lIjoiKzE2NTAxMjM1NTU1Iiwic3RyZWV0QWRkcmVzcyI6IjM0NSBTcGVhciBTdCIsImFkZHJlc3NMb2NhbGl0eSI6IlNhbiBGcmFuY2lzY28iLCJhZGRyZXNzUmVnaW9uIjoiQ0EiLCJwb3N0YWxDb2RlIjoiOTQxMDUiLCJhZGRyZXNzQ291bnRyeSI6IlVTIiwibGF0aXR1ZGUiOjM3LjQ3Mjg0MiwibG9uZ2l0dWRlIjotMTIyLjIxNzE0NH0=",
      "generation_timestamp": "2022-08-19T17:11:10.850Z"
    },
    {
      "data_record": "eyJAdHlwZSI6IlJlc3RhdXJhbnQiLCJAaWQiOiJyZXN0YXVyYW50MTIzIiwibmFtZSI6IlNvbWUgT3RoZXIgUmVzdGF1cmFudCIsInVybCI6Imh0dHBzOi8vd3d3LnByb3ZpZGVyLmNvbS9zb21lcmVzdGF1cmFudCIsInRlbGVwaG9uZSI6IisxNjUwMTIzMTIzNSIsInN0cmVldEFkZHJlc3MiOiIzODUgU3BlYXIgU3QiLCJhZGRyZXNzTG9jYWxpdHkiOiJTYW4gTWF0ZW8iLCJhZGRyZXNzUmVnaW9uIjoiQ0EiLCJwb3N0YWxDb2RlIjoiOTQxMTUiLCJhZGRyZXNzQ291bnRyeSI6IlVTIn0=",
      "generation_timestamp": "2022-08-19T17:11:10.850Z"
    }
  ]
}
    

ตัวอย่างที่ 3: การอัปเดตราคารายการในเมนู

สมมติว่าคุณต้องเปลี่ยนราคารายการเมนู

ลองใช้ฟีดแบบกลุ่มที่มีลักษณะดังนี้

{
  "@type": "MenuItemOffer",
  "@id": "menuitemoffer6680262",
  "sku": "offer-cola",
  "menuItemId": "menuitem896532",
  "price": 2,
  "priceCurrency": "USD"
}

จากนั้นการอัปเดตแบบเรียลไทม์ผ่าน POST จะเป็นดังนี้

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "MenuItemOffer",
        "@id": "menuitemoffer6680262",
        "sku": "offer-cola",
        "menuItemId": "menuitem896532",
        "price": 2,
        "priceCurrency": "USD"
      },
      "generation_timestamp": "2022-08-19T17:20:10Z"
    }
  ]
}
    

Base64

ตัวอย่างเดียวกับเพย์โหลดที่เข้ารหัส Base64

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "eyJAdHlwZSI6Ik1lbnVJdGVtT2ZmZXIiLCJAaWQiOiJtZW51aXRlbW9mZmVyNjY4MDI2MiIsInNrdSI6Im9mZmVyLWNvbGEiLCJtZW51SXRlbUlkIjoibWVudWl0ZW04OTY1MzIiLCJwcmljZSI6MiwicHJpY2VDdXJyZW5jeSI6IlVTRCJ9",
      "generation_timestamp": "2022-08-19T17:20:10Z"
    }
  ]
}

    

การเพิ่มเอนทิตี

อย่าใช้การอัปเดตแบบเรียลไทม์เพื่อเพิ่มเอนทิตีใหม่เนื่องจากอาจส่งผลให้ข้อมูลไม่ตรงกัน แต่ให้ใช้กระบวนการฟีดแบบกลุ่มตามที่อธิบายไว้สำหรับการนำเข้าเป็นกลุ่มแทน

การลบเอนทิตี

หากต้องการลบเอนทิตีออกจากพื้นที่โฆษณา ให้ใช้ปลายทางลบ และส่งคำขอ HTTP POST คำขอ POST แต่ละรายการต้องมีพารามิเตอร์ PARTNER_ID และเพย์โหลด JSON ที่มีตัวระบุเอนทิตีอยู่ในพื้นที่โฆษณา

ลบเพย์โหลดคำขอ

เนื้อหาของคำขอลบมีโครงสร้างคล้ายกับคำขออัปเดต และยังมีรายการระเบียนที่มีช่อง data_record และ delete_time ดังนี้

  {
    "records": [
      {
        "data_record":"BASE_64_ENCODED_REFERENCE",
        "delete_time": "DELETE_TIMESTAMP"
      }
    ]
  }

ในเพย์โหลดข้างต้น ให้แทนที่

  • BASE_64_ENCODED_REFERENCE: สตริง JSON ที่เข้ารหัส Base64 ของการอ้างอิงไปยังเอนทิตีที่กำลังนำออก ข้อมูลอ้างอิงจะมีแค่จากประเภทเอนทิตีและตัวระบุเท่านั้น เช่น การแสดงข้อมูลอ้างอิงใน MenuSection เป็น JSON ดังนี้

    {"@type":"MenuSection","@id":"853705"}
  • DELETE_TIMESTAMP: อย่าลืมใส่การประทับเวลาเมื่อมีการลบเอนทิตีในระบบแบ็กเอนด์ การประทับเวลานี้ใช้เพื่อกําหนดลำดับการลบจะมีผลกับพื้นที่โฆษณา

คำขอ batchDelete มีเอนทิตีได้สูงสุด 1,000 รายการ

ตัวอย่าง

ตัวอย่างที่ 1: การนำเอนทิตี MenuItem ออก 2 รายการ

หากต้องการนำรายการเมนู 2 รายการในการเรียก API เดียวออก คำขอ HTTP POST จะมีลักษณะดังนี้

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "MenuItem",
        "@id": "item_1234"
      },
      "delete_time": "2022-08-21T15:23:00.000Z"
    },
    {
      "data_record": {
        "@type": "MenuItem",
        "@id": "item_5678"
      },
      "delete_time": "2022-08-21T15:23:00.000Z"
    }
  ]
}
    

Base64

ตัวอย่างเดียวกับเพย์โหลดที่เข้ารหัส Base64

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "eyJAdHlwZSI6Ik1lbnVJdGVtIiwiQGlkIjoiaXRlbV8xMjM0In0="
      "delete_time": "2022-08-21T15:23:00.000Z"
    },
    {
      "data_record": "eyJAdHlwZSI6Ik1lbnVJdGVtIiwiQGlkIjoiaXRlbV81Njc4In0="
      "delete_time": "2022-08-21T15:23:00.000Z"
    },
  ]
}
    

ตัวอย่างที่ 2: การลบเอนทิตี Restaurant

พิจารณาสถานการณ์ที่คุณต้องการลบร้านอาหารในฟีดกลุ่ม คุณต้องลบเฉพาะเอนทิตีร้านอาหารเท่านั้น อย่าลบเอนทิตีย่อย เช่น บริการและเมนู เนื่องจากระบบจะนำออกโดยอัตโนมัติ

ตัวอย่างคำขอลบเอนทิตีร้านอาหารที่มีรหัส https://www.provider.com/restaurant/12345:

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "Restaurant",
        "@id": "https://www.provider.com/restaurant/12345"
      },
      "delete_time": "2022-08-19T17:11:10.750Z"
    }
  ]
}
    

Base64

ตัวอย่างเดียวกับเพย์โหลดที่เข้ารหัส Base64

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "ewogICJAdHlwZSI6ICJSZXN0YXVyYW50IiwKICAiQGlkIjogImh0dHBzOi8vd3d3LnByb3ZpZGVyLmNvbS9yZXN0YXVyYW50LzEyMzQ1Igp9"
      "delete_time": "2022-08-19T17:11:10.750Z"
    }
  ]
}
    

การตรวจสอบความถูกต้องและรหัสการตอบกลับ API

การตรวจสอบการเรียก API การอัปเดตแบบเรียลไทม์มี 2 ประเภทดังนี้

  • ระดับคำขอ - การตรวจสอบเหล่านี้จะตรวจสอบว่าเพย์โหลดเป็นไปตามสคีมา upsert หรือ ลบ และทุก data_record จะมีทั้งช่อง @id และ @type การตรวจสอบเหล่านี้เป็นแบบซิงโครนัสและระบบจะแสดงผลลัพธ์ในเนื้อหาการตอบสนองของ API โค้ดตอบกลับ 200 และเนื้อหา JSON ที่ว่างเปล่า {} หมายความว่าการตรวจสอบเหล่านี้ผ่านแล้ว และเอนทิตีในคำขอนั้นอยู่ในคิวเพื่อประมวลผลแล้ว โค้ดตอบกลับที่แตกต่างจาก 200 หมายความว่าการตรวจสอบอย่างน้อย 1 รายการล้มเหลวและคำขอทั้งหมดถูกปฏิเสธ (รวมถึงเอนทิตีทั้งหมดในเพย์โหลด) ตัวอย่างเช่น หาก data_record ไม่มี @type ระบบจะแสดงผลการตอบกลับข้อผิดพลาดต่อไปนี้

    {
      "error": {
        "code": 400,
        "message": "Record:{\"@id\":\"2717/86853/DELIVERY\",\"applicableServiceType\":[\"DELIVERY\",\"TAKEOUT\"],\"menuId\":[{\"@id\":\"2717/DELIVERY\",\"displayOrder\":1},{\"@id\":\"2717/TAKEOUT\",\"displayOrder\":2}],\"name\":\"Salad\",\"offeredById\":[\"2717\"]} has following errors: \nThe entity type could not be extracted from the entity value.\n",
        "status": "INVALID_ARGUMENT",
        "details": [
          {
            "@type": "type.googleapis.com/google.rpc.DebugInfo",
            "detail": "[ORIGINAL ERROR] generic::invalid_argument: Failed to parse one or more rtu records. Record:{\"@id\":\"2717/86853/DELIVERY\",\"applicableServiceType\":[\"DELIVERY\",\"TAKEOUT\"],\"menuId\":[{\"@id\":\"2717/DELIVERY\",\"displayOrder\":1},{\"@id\":\"2717/TAKEOUT\",\"displayOrder\":2}],\"name\":\"Salad\",\"offeredById\":[\"2717\"]} has following errors: \nThe entity type could not be extracted from the entity value.\n [google.rpc.error_details_ext] { message: \"Record:{\\\"@id\\\":\\\"2717/86853/DELIVERY\\\",\\\"applicableServiceType\\\":[\\\"DELIVERY\\\",\\\"TAKEOUT\\\"],\\\"menuId\\\":[{\\\"@id\\\":\\\"2717/DELIVERY\\\",\\\"displayOrder\\\":1},{\\\"@id\\\":\\\"2717/TAKEOUT\\\",\\\"displayOrder\\\":2}],\\\"name\\\":\\\"Salad\\\",\\\"offeredById\\\":[\\\"2717\\\"]} has following errors: \\nThe entity type could not be extracted from the entity value.\\n\" }"
          }
        ]
      }
    }
    
  • ระดับเอนทิตี - เอนทิตีแต่ละรายการในเพย์โหลดจะได้รับการตรวจสอบกับสคีมาเชิงสัมพันธ์ ปัญหาที่พบในขั้นตอนการตรวจสอบความถูกต้องนี้จะไม่ได้รับการรายงานในการตอบสนองของ API ระบบจะรายงานเฉพาะในหน้าแดชบอร์ดการรายงาน RTU

โควต้า API

การอัปเดต API แบบเรียลไทม์มีโควต้าคำขอ 1,500 รายการทุก 60 วินาที หรือ 25 คำขอต่อวินาทีโดยเฉลี่ย เมื่อเกินโควต้า Google จะตอบกลับด้วยข้อความแสดงข้อผิดพลาดต่อไปนี้

{
  "error": {
    "code": 429,
    "message": "Insufficient tokens for quota ...",
    "status": "RESOURCE_EXHAUSTED",
    "details": [...]
  }
}

หากต้องการแก้ไขปัญหานี้ ให้ลองโทรอีกครั้งโดยใช้ช่วงที่เพิ่มขึ้นแบบทวีคูณจนกว่าจะประสบความสำเร็จ หากคุณใช้โควต้าเป็นประจำ ให้พิจารณาเพิ่มเอนทิตีเพิ่มเติมในคำขอ API รายการเดียว คุณรวมเอนทิตีในการเรียก API ได้สูงสุด 1,000 รายการ

ตัวอย่างโค้ด

ด้านล่างคือตัวอย่างวิธีใช้ API การอัปเดตแบบเรียลไทม์ในภาษาต่างๆ ตัวอย่างเหล่านี้ใช้ไลบรารีการตรวจสอบสิทธิ์ของ Google เพื่อตรวจสอบสิทธิ์โดยใช้ไฟล์คีย์บัญชีบริการที่สร้างขึ้นระหว่างการตั้งค่าบัญชี สำหรับวิธีแก้ปัญหาทางเลือก โปรดดูที่การใช้ OAuth 2.0 สำหรับแอปพลิเคชันระหว่างเซิร์ฟเวอร์กับเซิร์ฟเวอร์ ลองใช้สคีมาที่มีในสร้างไลบรารีของไคลเอ็นต์เพื่อสร้างซอร์สโค้ดสำหรับประเภทออบเจ็กต์การอัปเดตพื้นที่โฆษณาและแบบเรียลไทม์

การอัปเดตเอนทิตี

Node.js

โค้ดนี้ใช้ไลบรารีการตรวจสอบสิทธิ์ของ Google สำหรับ Node.js

/* Sample code for Real-time update batchPush implementation.
 *
 * Required libraries:
 * - google-auth-library
 */

const {JWT} = require('google-auth-library');

// ACTION REQUIRED: Change this to the path of the service account client secret
// file downloaded from the Google Cloud Console.
const serviceAccountJson = require('./service-account.json');

// ACTION REQUIRED: Change this to your Partner ID received from Google.
// The Partner ID is available on the Partner Portal.
const PARTNER_ID = 1234;

const HOST = {
  prod: 'https://mapsbooking.googleapis.com',
  sandbox: 'https://partnerdev-mapsbooking.googleapis.com'
};

// ACTION REQUIRED: Change to 'prod' for production
const ENV = 'sandbox';

// Feed name for Order with Google including the version.
const FEED_NAME = 'owg.v2';

// Endpoint url
const url = `${HOST[ENV]}/v1alpha/inventory/partners/${PARTNER_ID}/feeds/${
    FEED_NAME}/record:batchPush`;

/**
 * Send a Real-time update request to update/insert entities
 */
async function batchUpsert(entities) {
  /**
   * Sign JWT token using private key from service account secret file
   * provided. The client can be created without providing a service account
   * secret file by implementing Application Default Credentials.
   * https://github.com/googleapis/google-auth-library-nodejs
   */
  const client = new JWT({
    email: serviceAccountJson.client_email,
    key: serviceAccountJson.private_key,
    scopes: ['https://www.googleapis.com/auth/mapsbooking'],
  });
  const request = {records: toPushRecords(entities)};
  const body = JSON.stringify(request);
  try {
    const response = await client.request({
      method: 'POST',
      url,
      data: body,
      headers: {'Content-Type': 'application/json'}
    });
    console.log('request body:', body);
    console.log('response status:', response.status);
    console.log(
        'response data:', response.data);  // successful response returns '{}'
  } catch (error) {
    console.log('error:', error);
  }
}

/**
 * Maps array of entities to records for batch push requests
 */
const toPushRecords = (entities) => {
  return entities.map((entity) => {
    // Using dateModified to set generation_timestamp. Defaulting to the
    // current timestamp for records that do not have dateModified.
    const generation_timestamp =
        entity.dateModified ? entity.dateModified : new Date().toISOString();
    return {data_record: btoa(JSON.stringify(entity)), generation_timestamp};
  });
};

// Call batchUpsert with example entities. dateModified is optional and is
// used to hold the actual timestamp when the entity was updated/created.
batchUpsert([
  {
    '@type': 'MenuItemOffer',
    '@id': '6680261',
    'menuItemId': '18931508',
    'price': 15.5,
    'priceCurrency': 'USD',
    'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
    'inventoryLevel': 0,
    'dateModified': '2022-06-19T15:43:50.970Z'
  },
  {
    '@type': 'MenuItemOffer',
    '@id': '6680262',
    'menuItemId': '18931509',
    'price': 25.5,
    'priceCurrency': 'USD',
    'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
    'inventoryLevel': 0,
    'dateModified': '2022-06-19T15:43:50.970Z'
  }
]);

Python

โค้ดนี้ใช้ไลบรารีการตรวจสอบสิทธิ์ของ Google สำหรับ Python

"""Sample code for the Real-time update batchPush implementation."""

# Required libraries:
# - google-auth

import base64
import datetime
import json
from google.auth.transport.requests import AuthorizedSession
from google.oauth2 import service_account

# ACTION REQUIRED: Change this to the Partner ID received from Google.
# Partner ID is available on the Partner Portal.
# https://partnerdash.google.com/apps/reservewithgoogle
_PARTNER_ID = '1234'

# ACTION REQUIRED: Change this to the path of the service account client secret
# file downloaded from the Google Cloud Console.
_SERVICE_ACCOUNT_KEY_JSON_FILE = 'service-account-creds.json'

_HOST_MAP = {
    'sandbox': 'https://partnerdev-mapsbooking.googleapis.com',
    'prod': 'https://mapsbooking.googleapis.com'
}

# ACTION REQUIRED: Change to 'prod' for production
_ENV = 'sandbox'

# Feed name for Order with Google including the version.
_FEED_NAME = 'owg.v2'

_ENDPOINT = '{}/v1alpha/inventory/partners/{}/feeds/{}/record:batchPush'.format(
    _HOST_MAP[_ENV], _PARTNER_ID, _FEED_NAME)


def batch_upsert(entities):
  """Makes a batchPush request using the Real-time updates REST service.

  Args:
      entities: The list of entity objects to update or add.
  """

  # Creates credentials by providing a json file. Credentials can also be
  # provided by implementing Application Default Credentials.
  # https://googleapis.dev/python/google-auth/latest/user-guide.html
  credentials = service_account.Credentials.from_service_account_file(
      _SERVICE_ACCOUNT_KEY_JSON_FILE,
      scopes=['https://www.googleapis.com/auth/mapsbooking'])
  authorized_session = AuthorizedSession(credentials)

  # JSON request object
  batch_request = {'records': [create_push_record(x) for x in entities]}
  response = authorized_session.post(_ENDPOINT, json=batch_request)
  print('request body:', json.dumps(batch_request))
  print('response status:', response.status_code)
  print('response data:', response.text)  # successful response returns '{}'


def create_push_record(entity):
  """Creates a record from an entity for batchPush requests.

  Args:
      entity: The entity object to create the record from.

  Returns:
      The constructed record for the batchPush request payload.
  """
  data_bytes = json.dumps(entity).encode('utf-8')
  base64_bytes = base64.b64encode(data_bytes)
  # Using dateModified to set generation_timestamp. Defaulting to the
  # current timestamp for records that do not have dateModified.
  generation_timestamp = entity.dateModified if 'dateModified' in entity else datetime.datetime.now(
  ).strftime('%Y-%m-%dT%H:%M:%S.%fZ')
  return {
      'generation_timestamp': generation_timestamp,
      'data_record': base64_bytes.decode('utf-8')
  }


# Call batch_upsert with example entities. dateModified is optional and is
# used to hold the actual timestamp when the entity was updated/created.
batch_upsert([{
    '@type': 'MenuItemOffer',
    '@id': '6680261',
    'menuItemId': '18931508',
    'price': 15.5,
    'priceCurrency': 'USD',
    'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
    'inventoryLevel': 0,
    'dateModified': '2022-06-19T15:43:50.970Z'
}, {
    '@type': 'MenuItemOffer',
    '@id': '6680262',
    'menuItemId': '18931509',
    'price': 25.5,
    'priceCurrency': 'USD',
    'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
    'inventoryLevel': 0,
    'dateModified': '2022-06-19T15:43:50.970Z'
}])

Java

รหัสนี้ใช้ไลบรารีการตรวจสอบสิทธิ์ของ Google สำหรับ Java

สร้างโมเดลซอร์สโค้ดของไคลเอ็นต์ในแพ็กเกจ rtusamples.inventory และ rtusamples.realtime แล้วโดยทำตามขั้นตอนในสร้างไลบรารีของไคลเอ็นต์

/*
 * Required Libraries:
 * - JDK >= 11
 * - google-auth-library-oauth2-http
 */
package rtusamples;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.Charset;
import java.time.Clock;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import rtusamples.inventory.MenuItemOffer;
import rtusamples.inventory.MenuItemOfferType;
import rtusamples.inventory.ServiceTypeElement;
import rtusamples.realtime.BatchPushGenericRecordRequest;
import rtusamples.realtime.GenericRecord;

/** Sample code for Real-time update batchPush implementation. */
public final class BasicPush {
  // ACTION REQUIRED: Change this to your Partner ID received from Google. The Partner ID is
  // available on the Partner Portal.
  private static final long PARTNER_ID = 12345678;

  // ACTION REQUIRED: Change this to the path of the service account client secret file downloaded
  // from the Google Cloud Console.
  private static final String JSON_KEY_FULL_PATH =
      "<path to your JSON credentials>/credentials.json";

  // ACTION REQUIRED: Change this to the endpoint that is needed.
  private static final String ENDPOINT =
      //    "https://partnerdev-mapsbooking.googleapis.com"; // for sandbox
      "https://mapsbooking.googleapis.com"; // for prod

  // Feed name for Order with Google including the version.
  private static final String FEED_NAME = "owg.v2";

  private static final ObjectMapper objectMapper = new ObjectMapper();

  private static final DateTimeFormatter TIMESTAMP_FORMATTER =
      DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSS]'Z'");

  private static final Charset UTF_8 = Charset.forName("UTF-8");

  public static void main(String[] args) throws Exception {

    /**
     * Create credentials from service account secret file. Alternatively, the credentials can be
     * created by implementing Application Default Credentials.
     * https://github.com/googleapis/google-auth-library-java
     */
    // GoogleCredentials sourceCredentials =
    //     GoogleCredentials.getApplicationDefault()
    //         .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

    // ImpersonatedCredentials credentials =
    //     ImpersonatedCredentials.create(
    //         sourceCredentials,
    //         "fo-test@projectname.iam.gserviceaccount.com",
    //         null,
    //         Arrays.asList("https://www.googleapis.com/auth/mapsbooking"),
    //         300);

    GoogleCredentials credentials =
        GoogleCredentials.fromStream(new FileInputStream(JSON_KEY_FULL_PATH))
            .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

    // Create example MenuItemOffer entities, dateModified is optional and is used to hold
    // the actual timestamp when the entity was updated/created.
    MenuItemOffer menuItemOfferPizza = new MenuItemOffer();
    menuItemOfferPizza.setID("6680261");
    menuItemOfferPizza.setType(MenuItemOfferType.MENU_ITEM_OFFER);
    menuItemOfferPizza.setMenuItemID("18931508");
    menuItemOfferPizza.setPrice(15.5);
    menuItemOfferPizza.setPriceCurrency("USD");
    menuItemOfferPizza.setApplicableServiceType(
        new ServiceTypeElement[] {ServiceTypeElement.TAKEOUT, ServiceTypeElement.DELIVERY});
    menuItemOfferPizza.setInventoryLevel(0.0);
    menuItemOfferPizza.setDateModified("2022-10-07T13:00:00.000Z");

    MenuItemOffer menuItemOfferSalad = new MenuItemOffer();
    menuItemOfferSalad.setID("6680262");
    menuItemOfferSalad.setType(MenuItemOfferType.MENU_ITEM_OFFER);
    menuItemOfferSalad.setMenuItemID("18931509");
    menuItemOfferSalad.setPrice(25.5);
    menuItemOfferSalad.setPriceCurrency("USD");
    menuItemOfferSalad.setApplicableServiceType(
        new ServiceTypeElement[] {ServiceTypeElement.TAKEOUT, ServiceTypeElement.DELIVERY});
    menuItemOfferSalad.setInventoryLevel(0.0);
    menuItemOfferSalad.setDateModified("2022-10-07T13:00:00.000Z");

    // Example array of MenuItemOffer entities to update.
    List<MenuItemOffer> menuItemOffers = Arrays.asList(menuItemOfferPizza, menuItemOfferSalad);

    // Create list of GenericRecord from menuItemOffers.
    List<GenericRecord> menuItemOfferGenericRecords =
        menuItemOffers.stream()
            .map(
                (menuItemOffer) ->
                    toBatchPushRecord(menuItemOffer, menuItemOffer.getDateModified()))
            .collect(Collectors.toList());

    // List of records to be updated/created.
    List<GenericRecord> recordsToBeUpdated = new ArrayList<>();

    // Add list of menuItemOffer generic records.
    recordsToBeUpdated.addAll(menuItemOfferGenericRecords);

    // Request object that contains all records.
    BatchPushGenericRecordRequest batchPushRequest = new BatchPushGenericRecordRequest();
    batchPushRequest.setRecords(recordsToBeUpdated.toArray(new GenericRecord[0]));

    // Execute batchPush request.
    BasicPush basicPush = new BasicPush();
    basicPush.batchPush(batchPushRequest, credentials);
  }

  public void batchPush(
      BatchPushGenericRecordRequest batchPushRequest, GoogleCredentials credentials)
      throws IOException {

    credentials.refreshIfExpired();
    AccessToken token = credentials.getAccessToken();

    String requestBody = objectMapper.writeValueAsString(batchPushRequest);
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request =
        HttpRequest.newBuilder()
            .uri(
                URI.create(
                    String.format(
                        "%s/v1alpha/inventory/partners/%s/feeds/%s/record:batchPush",
                        ENDPOINT, PARTNER_ID, FEED_NAME)))
            .header("Content-Type", "application/json")
            .header("Authorization", String.format("Bearer %s", token.getTokenValue()))
            .POST(BodyPublishers.ofString(requestBody))
            .build();

    HttpResponse<String> response = null;
    try {
      response = client.send(request, BodyHandlers.ofString());
      System.out.println("Request body:" + requestBody);
      System.out.println("Response status:" + response.statusCode());
      System.out.println("Response body:" + response.body());
    } catch (IOException | InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static <T> GenericRecord toBatchPushRecord(T entity, String dateModified) {
    GenericRecord genericRecord = new GenericRecord();
    try {
      String json = objectMapper.writeValueAsString(entity);
      genericRecord.setDataRecord(Base64.getEncoder().encodeToString(json.getBytes(UTF_8)));
      // Using dateModified to set generation_timestamp. Defaulting to the
      // current timestamp for records that do not have dateModified.
      String generationTimestamp =
          Optional.ofNullable(dateModified)
              .orElse(OffsetDateTime.now(Clock.systemUTC()).format(TIMESTAMP_FORMATTER));
      genericRecord.setGenerationTimestamp(generationTimestamp);
    } catch (JsonProcessingException e) {
      System.out.println(e.getMessage());
    }
    return genericRecord;
  }
}

การนำเอนทิตีออก

Node.js

โค้ดนี้ใช้ไลบรารีการตรวจสอบสิทธิ์ของ Google สำหรับ Node.js

/* Sample code for Real-time update batchDelete implementation.
 *
 * Required libraries:
 * - google-auth-library
 */

const {JWT} = require('google-auth-library');

// ACTION REQUIRED: Change this to the path of the service account client secret
// file downloaded from the Google Cloud Console.
const serviceAccountJson = require('./service-account.json');

// ACTION REQUIRED: Change this to your Partner ID received from Google.
// The Partner ID is available on the Partner Portal.
const PARTNER_ID = 1234;

const HOST = {
  prod: 'https://mapsbooking.googleapis.com',
  sandbox: 'https://partnerdev-mapsbooking.googleapis.com'
};

// ACTION REQUIRED: Change to 'prod' for production
const ENV = 'sandbox';

// Feed name for Order with Google including the version.
const FEED_NAME = 'owg.v2';

// Endpoint url
const url = `${HOST[ENV]}/v1alpha/inventory/partners/${PARTNER_ID}/feeds/${
    FEED_NAME}/record:batchDelete`;


/**
 * Send a Real-time update request to delete entities
 */
async function batchDelete(entities) {
  try {
    /**
     * Sign JWT token using private key from service account secret file
     * provided. The client can be created without providing a service account
     * secret file by implementing Application Default Credentials.
     * https://github.com/googleapis/google-auth-library-nodejs
     */
    const client = new JWT({
      email: serviceAccountJson.client_email,
      key: serviceAccountJson.private_key,
      scopes: ['https://www.googleapis.com/auth/mapsbooking'],
    });
    const request = {
      records: toDeleteRecords(entities)
    };
    const body = JSON.stringify(request);
    try {
      const response = await client.request({
        method: 'POST',
        url,
        data: body,
        headers: {'Content-Type': 'application/json'}
      });
      console.log('request body:', body);
      console.log('response status:', response.status);
      console.log('response data:', response.data);  // successful response returns '{}'
    } catch (error) {
      console.log('error:', error);
    }
  }

  /**
   * Maps array of entities to records for batch delete requests
   */
  const toDeleteRecords = (entities) => {
    return entities.map((entity) => {
      // Using dateModified to set delete_time. Defaulting to the current
      // timestamp for records that do not have dateModified.
      const delete_time =
          entity.dateModified ? entity.dateModified : new Date().toISOString();
      return {data_record: btoa(JSON.stringify(entity)), delete_time};
    });
  };

  // Call batchDelete with example entities. dateModified is optional and is
  // used to hold the actual timestamp when the entity was deleted.
  batchDelete([
    {
      '@type': 'Menu',
      '@id': '853706',
      'dateModified': '2022-06-19T15:43:50.970Z'
    },
    {
      '@type': 'Menu',
      '@id': '853705',
      'dateModified': '2022-06-19T15:13:00.280Z'
    }
  ]);

Python

โค้ดนี้ใช้ไลบรารีการตรวจสอบสิทธิ์ของ Google สำหรับ Python

"""Sample code for the Real-time update batchDelete implementation."""

# Required libraries:
# - google-auth

import base64
import datetime
import json
from google.auth.transport.requests import AuthorizedSession
from google.oauth2 import service_account

# ACTION REQUIRED: Change this to the Partner ID received from Google.
# Partner ID is available on the Partner Portal.
# https://partnerdash.google.com/apps/reservewithgoogle
_PARTNER_ID = '1234'

# ACTION REQUIRED: Change this to the path of the service account client secret
# file downloaded from the Google Cloud Console.
_SERVICE_ACCOUNT_KEY_JSON_FILE = 'service-account-creds.json'

_HOST_MAP = {
    'sandbox': 'https://partnerdev-mapsbooking.googleapis.com',
    'prod': 'https://mapsbooking.googleapis.com'
}

# ACTION REQUIRED: Change to 'prod' for production
_ENV = 'sandbox'

# Feed name for Order with Google including the version.
_FEED_NAME = 'owg.v2'

_ENDPOINT = '{}/v1alpha/inventory/partners/{}/feeds/{}/record:batchDelete'.format(
    _HOST_MAP[_ENV], _PARTNER_ID, _FEED_NAME)


def batch_delete(entities):
  """Makes a batch delete request using the Real-time updates REST service.

  Args:
      entities: The list of entity objects to delete.
  """

  # Creates credentials by providing a json file. Credentials can also be
  # provided by implementing Application Default Credentials.
  # https://googleapis.dev/python/google-auth/latest/user-guide.html
  credentials = service_account.Credentials.from_service_account_file(
      _SERVICE_ACCOUNT_KEY_JSON_FILE,
      scopes=['https://www.googleapis.com/auth/mapsbooking'])
  authorized_session = AuthorizedSession(credentials)

  # JSON request object
  batch_request = {'records': [create_delete_record(x) for x in entities]}
  response = authorized_session.post(_ENDPOINT, json=batch_request)
  print('request body:', json.dumps(batch_request))
  print('response status:', response.status_code)
  print('response data:', response.text)  # successful response returns '{}'


def create_delete_record(entity):
  """Creates a record from an entity for batchDelete requests.

  Args:
    entity: The entity object to create the record from.

  Returns:
    The constructed record for the batchDelete request payload.
  """
  data_bytes = json.dumps(entity).encode('utf-8')
  base64_bytes = base64.b64encode(data_bytes)
  # Using dateModified to set delete_time. Defaulting to the current
  # timestamp for records that do not have dateModified.
  delete_time = entity.dateModified if 'dateModified' in entity else datetime.datetime.now(
  ).strftime('%Y-%m-%dT%H:%M:%S.%fZ')
  return {
      'delete_time': delete_time,
      'data_record': base64_bytes.decode('utf-8')
  }


# Call batch_delete with example entities. dateModified is optional and is
# used to hold the actual timestamp when the entity was deleted.
batch_delete([{
    '@type': 'Menu',
    '@id': '853706',
    'dateModified': '2022-06-19T13:10:00.000Z'
}, {
    '@type': 'Menu',
    '@id': '853705',
    'dateModified': '2022-06-19T13:30:10.000Z'
}])

Java

รหัสนี้ใช้ไลบรารีการตรวจสอบสิทธิ์ของ Google สำหรับ Java

สร้างโมเดลซอร์สโค้ดของไคลเอ็นต์ในแพ็กเกจ rtusamples.inventory และ rtusamples.realtime แล้วโดยทำตามขั้นตอนในสร้างไลบรารีของไคลเอ็นต์

/*
 * Required Libraries:
 * - JDK >= 11
 * - google-auth-library-oauth2-http
 */
package rtusamples;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.Charset;
import java.time.Clock;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import rtusamples.inventory.Menu;
import rtusamples.inventory.MenuType;
import rtusamples.realtime.BatchDeleteGenericRecordsRequest;
import rtusamples.realtime.GenericDeleteRecord;

/** Sample code for the Real-time update batchDelete implementation. */
public final class BasicDelete {
  // ACTION REQUIRED: Change this to your Partner ID received from Google. The Partner ID is
  // available on the Partner Portal.
  private static final long PARTNER_ID = 123456789;

  // ACTION REQUIRED: Change this to the path of the service account client secret file downloaded
  // from the Google Cloud Console.
  private static final String JSON_KEY_FULL_PATH =
      "<path to your JSON credentials>/credentials.json";

  // ACTION REQUIRED: Change this to the endpoint that is needed.
  private static final String ENDPOINT =
      "https://partnerdev-mapsbooking.googleapis.com"; // for sandbox
  // "https://mapsbooking.googleapis.com" // for prod

  // Feed name for Order with Google including the version.
  private static final String FEED_NAME = "owg.v2";

  private static final ObjectMapper objectMapper = new ObjectMapper();

  private static final DateTimeFormatter TIMESTAMP_FORMATTER =
      DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSS]'Z'");

  private static final Charset UTF_8 = Charset.forName("UTF-8");

  public static void main(String[] args) throws Exception {

    /**
     * Create credentials from service account secret file. Alternatively, the credentials can be
     * created by implementing Application Default Credentials.
     * https://github.com/googleapis/google-auth-library-java
     */
    // GoogleCredentials sourceCredentials =
    //     GoogleCredentials.getApplicationDefault()
    //         .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

    // ImpersonatedCredentials credentials =
    //     ImpersonatedCredentials.create(
    //         sourceCredentials,
    //         "fo-test@projectname.iam.gserviceaccount.com",
    //         null,
    //         Arrays.asList("https://www.googleapis.com/auth/mapsbooking"),
    //         300);

    GoogleCredentials credentials =
        GoogleCredentials.fromStream(new FileInputStream(JSON_KEY_FULL_PATH))
            .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

    // Create example Menu entities, dateModified is optional and is used to hold
    // the actual timestamp when the entity was deleted.
    Menu menuLunch = new Menu();
    menuLunch.setID("853705");
    menuLunch.setType(MenuType.MENU);
    menuLunch.setDateModified("2022-09-19T13:10:00.000Z");

    Menu menuDinner = new Menu();
    menuDinner.setID("853706");
    menuDinner.setType(MenuType.MENU);
    menuDinner.setDateModified("2022-09-19T13:13:10.000Z");

    // Example array of Menu entities to update.
    List<Menu> menus = Arrays.asList(menuLunch, menuDinner);

    // Create list of GenericDeleteRecord from menus.
    List<GenericDeleteRecord> menuGenericDeleteRecords =
        menus.stream()
            .map((menu) -> toBatchDeleteRecord(menu, menu.getDateModified()))
            .collect(Collectors.toList());

    // List of records to be deleted.
    List<GenericDeleteRecord> recordsToBeDeleted = new ArrayList<>();

    // Add list of menu generic records.
    recordsToBeDeleted.addAll(menuGenericDeleteRecords);

    // Request object that contains all records.
    BatchDeleteGenericRecordsRequest batchDeleteRequest = new BatchDeleteGenericRecordsRequest();
    batchDeleteRequest.setRecords(recordsToBeDeleted.toArray(new GenericDeleteRecord[0]));

    // Execute batchDelete request.
    BasicDelete basicDelete = new BasicDelete();
    basicDelete.batchDelete(batchDeleteRequest, credentials);
  }

  public void batchDelete(
      BatchDeleteGenericRecordsRequest batchDeleteRequest, GoogleCredentials credentials)
      throws IOException {

    credentials.refreshIfExpired();
    AccessToken token = credentials.getAccessToken();

    String requestBody = objectMapper.writeValueAsString(batchDeleteRequest);
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request =
        HttpRequest.newBuilder()
            .uri(
                URI.create(
                    String.format(
                        "%s/v1alpha/inventory/partners/%s/feeds/%s/record:batchDelete",
                        ENDPOINT, PARTNER_ID, FEED_NAME)))
            .header("Content-Type", "application/json")
            .header("Authorization", String.format("Bearer %s", token.getTokenValue()))
            .POST(BodyPublishers.ofString(requestBody))
            .build();

    HttpResponse<String> response = null;
    try {
      response = client.send(request, BodyHandlers.ofString());
      System.out.println("Request body:" + requestBody);
      System.out.println("Response status:" + response.statusCode());
      System.out.println("Response body:" + response.body());
    } catch (IOException | InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static <T> GenericDeleteRecord toBatchDeleteRecord(T entity, String dateModified) {
    GenericDeleteRecord genericRecord = new GenericDeleteRecord();
    try {
      String json = objectMapper.writeValueAsString(entity);
      genericRecord.setDataRecord(Base64.getEncoder().encodeToString(json.getBytes(UTF_8)));
      // Using dateModified to set delete_time. Defaulting to the current
      // timestamp for records that do not have dateModified.
      String deleteTime =
          Optional.ofNullable(dateModified)
              .orElse(OffsetDateTime.now(Clock.systemUTC()).format(TIMESTAMP_FORMATTER));
      genericRecord.setDeleteTime(deleteTime);
    } catch (JsonProcessingException e) {
      System.out.println(e.getMessage());
    }
    return genericRecord;
  }
}

Use Case

กรณีการใช้งานต่อไปนี้คือตัวอย่างของการอัปเดตแบบเรียลไทม์ การอัปเดตฟีดแบบกลุ่ม และเนื้อหาที่ระดับสูงในการเรียก API

สถานการณ์ เอนทิตีที่จะอัปเดต คำอธิบายและเอฟเฟกต์
การปิดใช้บริการ Service

คุณต้องปิดใช้บริการโดยไม่ทราบสาเหตุ

การอัปเดตแบบเรียลไทม์: อัปเดตเอนทิตี Service ที่เป็นปัญหาโดยตั้งค่าพร็อพเพอร์ตี้ isDisabled เป็น true แต่คงพร็อพเพอร์ตี้อื่นๆ ไว้เหมือนเดิม

ฟีดแบบสมบูรณ์: ตรวจสอบว่าได้อัปเดตเอนทิตีจากฟีดแบบเต็มให้ตั้งค่า isDisabled เป็น true ก่อนการดึงข้อมูลครั้งถัดไปโดย Google มิเช่นนั้นระบบจะเปิดใช้เอนทิตีอีกครั้ง

สินค้าบางรายการหมดสต็อก MenuItemOffer การอัปเดตแบบเรียลไทม์: ส่งเอนทิตี MenuItemOffer ที่รวมอยู่โดยที่ตั้งค่า inventoryLevel เป็น 0 สำหรับ MenuItem ที่ระบุ และข้อมูลอื่นๆ ทั้งหมดไม่เปลี่ยนแปลง
การเปลี่ยนแปลงราคารายการในเมนู MenuItemOffer การอัปเดตแบบเรียลไทม์: ส่งเอนทิตี MenuItemOffer ที่รวมอยู่โดยที่ตั้งค่า price เป็นราคาที่อัปเดตสำหรับ MenuItem ที่ระบุและข้อมูลอื่นๆ ทั้งหมดโดยไม่มีการเปลี่ยนแปลง

เพิ่มเอนทิตีระดับบนสุดใหม่

ใช้ได้กับเอนทิตีประเภท Menu, Restaurant และ Service เท่านั้น

Menu, Restaurant, Service

ตัวอย่างเช่น คุณต้องเพิ่มเมนูใหม่ไปที่ร้านอาหาร

ฟีดแบบสมบูรณ์: เพิ่มเอนทิตีในฟีดข้อมูลและรอการนำเข้าแบบกลุ่ม

ลบเอนทิตีระดับบนสุดอย่างถาวร

ใช้ได้กับเอนทิตีประเภท Menu, Restaurant และ Service เท่านั้น

Menu, Restaurant, Service

การอัปเดตแบบเรียลไทม์: ส่งการลบข้อมูลอย่างชัดแจ้ง

ฟีดแบบสมบูรณ์: ตรวจสอบว่าได้นําเอนทิตีออกจากฟีดที่สมบูรณ์แล้วก่อนที่ Google จะดึงข้อมูลครั้งถัดไป มิเช่นนั้นระบบจะเพิ่มเอนทิตีนั้นอีกครั้ง

เพิ่มพื้นที่นำส่งใหม่ในพื้นที่ Service ที่เจาะจง ServiceArea ฟีดกลุ่ม: ส่งเอนทิตี ServiceArea ที่เป็นปัญหาโดยที่ช่องทั้งหมดของเอนทิตีนั้นสมบูรณ์เหมือนปกติ เหมือนที่คุณทำในฟีดที่สมบูรณ์ตามปกติ และระบุพื้นที่นำส่งใหม่ภายใน polygon, geoRadius หรือ postalCode
อัปเดตเวลาถึงที่นำส่งโดยประมาณใน Service ServiceHours ฟีดแบบกลุ่ม: ส่ง ServiceHours เหมือนกับในฟีด เว้นแต่จะอัปเดต leadTimeMin ให้สอดคล้องกัน
อัปเดตราคาการจัดส่งในสกุลเงิน Service Fee ฟีดแบบกลุ่ม: ส่ง Fee สำหรับการนำส่งแบบเต็มโดยมีการอัปเดต price
อัปเดตเวลาให้บริการส่งหรือสั่งกลับบ้านใน Service ServiceHours ฟีดกลุ่ม: ส่ง ServiceHours เหมือนกับในฟีด เว้นแต่จะอัปเดตพร็อพเพอร์ตี้ opens และ closes ให้สอดคล้องกัน
Service (เปลี่ยนจำนวนการสั่งซื้อขั้นต่ำ) Fee ฟีดกลุ่ม: ส่ง Fee เต็มรูปแบบพร้อมอัปเดต minPrice แล้ว
ลบ MenuItem อย่างถาวร Menu ฟีดแบบกลุ่ม: ส่ง MenuItem เหมือนกับในฟีด แต่ว่างเปล่า parentMenuSectionId

เวลาในการประมวลผลสำหรับงานแบบกลุ่มและการอัปเดตแบบเรียลไทม์

เอนทิตีที่อัปเดตหรือลบผ่านฟีดกลุ่มจะได้รับการประมวลผลภายใน 2 ชั่วโมง ขณะที่เอนทิตีที่อัปเดตผ่านการอัปเดตแบบเรียลไทม์จะได้รับการประมวลผลภายใน 5 นาที เอนทิตีที่ไม่มีอัปเดตจะถูกลบภายใน 14 วัน

คุณจะส่งรายการต่อไปนี้ให้ Google ได้

  • งานแบบกลุ่มหลายๆ งานต่อวันเพื่ออัปเดตสินค้าคงคลังให้เป็นปัจจุบันอยู่เสมอ หรือ
  • งานแบบกลุ่ม 1 งานต่อวันและอัปเดตแบบเรียลไทม์เพื่อให้สินค้าคงคลังเป็นปัจจุบันอยู่เสมอ