JSON Toolkit

JSONPath ফিল্টার গভীরে: পুনরাবৃত্তি, স্লাইস ও বহু-শর্ত মিলান

সংক্ষেপে: পুনরাবৃত্ত ডিসেন্ট, স্লাইস ও বহু-শর্ত ফিল্টার — এখানেই JSONPath শক্তিশালী হয় আর ভুল ব্যবহার হয়। ফিল্টার সেমান্টিক্স, ফলের আকৃতি ও লাইব্রেরির পার্থক্য।

মধ্যবর্তী~10 মিনিট পড়াপ্রকাশ 2026-10-31আপডেট 2026-10-31
JSONPath ফিল্টার গভীরে নিবন্ধের কভার

মূল কথা: আগে জানা গভীরতায় লোকেট করুন, তারপর স্লাইস ও ফিল্টার যোগ করুন, $..-এর দিকে হাত বাড়াবেন না; ফিল্টারে খালি পাথ কেবল অস্তিত্ব পরীক্ষা করে, তাই বুলিয়ান পরীক্ষা করতে @.stock == true লিখুন।

যে কেউ $.store.book[0].title লিখতে পারে। JSONPath আসলে ভাঙে $..-কে স্লাইস ও একাধিক শর্তের সঙ্গে মিলিয়ে, তারপর অতিরিক্ত ফল, অপর্যাপ্ত ফল, বা প্রত্যাশিত নয় এমন ক্রম পাওয়ায়।

১. একটি নমুনা ডকুমেন্ট

{
  "store": {
    "book": [
      { "title": "JSON: The Definitive Guide", "price": 8.95, "stock": true, "tags": ["json", "spec"] },
      { "title": "A History of Data Formats", "price": 12.99, "stock": false, "tags": ["history"] },
      { "title": "How Parsers Work", "price": 8.99, "stock": true, "tags": ["parser", "json"] },
      { "title": "Streaming JSON in Practice", "price": 9.5, "stock": true, "tags": [] }
    ],
    "bicycle": { "color": "red", "price": 19.95 }
  },
  "updatedAt": "2026-10-31"
}

নিচের প্রতিটি এক্সপ্রেশন এই ডকুমেন্ট ইনপুট ধরে। দুটি প্রস্তাবনা মনে রাখুন: ফল একটি নোড সেট, আর এর ক্রম ডকুমেন্টের ক্রম অনুসরণ করে, শর্ত লেখার ক্রম নয়। ফিল্টারের ভেতরে @ কেবল চলতি প্রার্থী নোডে ইশারা করে।

২. পুনরাবৃত্ত ডিসেন্ট $..: সুবিধাজনক কিন্তু দামি

.. মানে "চলতি অবস্থান থেকে যেকোনো গভীরে পুনরাবৃত্তভাবে খোঁজো"। RFC 9535 এটিকে ডিসেন্ড্যান্ট সেগমেন্ট সংজ্ঞায়িত করে, আর এটি নাম, ওয়াইল্ডকার্ড, ইনডেক্স, স্লাইস ও ফিল্টারের সঙ্গে মেলা যায়:

$..price                  // every member named price at any depth
$..book[?(@.price < 10)]  // any book at any depth, then filter
$..[?(@.stock)]           // any node at any depth where stock exists

তিনটি বিষয় বুঝুন:

  1. $..book book নামের প্রতিটি নোড খোঁজে, গভীরতা যাই হোক;
  2. ট্রাভার্সাল ডেপথ-ফার্স্ট, আর আউটপুট ক্রম নির্ভর করে বাস্তবায়ন কীভাবে শিশু পরিদর্শন করে;
  3. .. কোনো ইনডেক্স ব্যবহার করতে পারে না, তাই এর খরচ মোট নোড সংখ্যার সঙ্গে বাড়ে।

ফলে $..price ও $.store.book[*].price-এর আউটপুট হয়তো কেবল সাইকেলের দামে আলাদা, তবু খরচে এক মাত্রার ক্রমে আলাদা। গভীরতা জানলে সবসময় স্পষ্ট পাথ লিখুন। দুই পাথ-ভাষার সীমানা তুলনা করতে চাইলে দেখুন JSONPath বনাম JSON Pointer।

৩. অ্যারে স্লাইস ও ওয়াইল্ডকার্ড: তিনটি ফাঁদ

স্লাইস সিনট্যাক্স [start:end:step], শুরু অন্তর্ভুক্ত ও শেষ বাদ, ঋণাত্মক সংখ্যা লেজ থেকে গোনে:

এক্সপ্রেশন অর্থ ফল (চার বইয়ে)
[0:2] প্রথম দুই বই বই ১ ও ২
[1:] দ্বিতীয় বই থেকে শেষ পর্যন্ত বই ২, ৩ ও ৪
[:2] প্রথম দুই বই বই ১ ও ২
[-2:] শেষ দুই বই বই ৩ ও ৪
[::2] এক ছাড়িয়ে আরেক বই ১ ও ৩
[::-1] উল্টো ক্রম বই ৪, ৩, ২ ও ১

তিনটি ফাঁদ:

  • শূন্য ধাপ অবৈধ। RFC 9535 অশূন্য ধাপ বাধ্যতামূলক করে, অথচ কিছু বাস্তবায়ন নীরবে খালি সেট ফেরত দেয়;
  • ঋণাত্মক ধাপ সর্বত্র সমর্থিত নয়। মূল গেসনার বাস্তবায়ন সমর্থন করে, কিন্তু কিছু ন্যূনতম বাস্তবায়ন কেবল ধনাত্মক ধাপ গ্রহণ করে;
  • স্লাইসের পর ফিল্টার পরিধি বাড়ায় না। [0:2][?(@.stock)] কেবল স্লাইসের উৎপন্ন দুই বই ফিল্টার করে; পুরো অ্যারেতে ফিরে যায় না।

ওয়াইল্ডকার্ড [*] স্লাইসের সঙ্গে মেলা যায়, কিন্তু [*] "সব চাইল্ড নোড" দেয়। ওই শিশুরা অবজেক্ট হলে .title যোগ করলে সব শিরোনাম পাওয়া যায়। কোনো শিশু নিজেই অ্যারে হলে .title আরেক স্তর স্বয়ংক্রিয়ভাবে ফ্ল্যাটেন করবে না। প্রসারিত করতে হলে আবার [*] লিখুন; স্বয়ংক্রিয় ফ্ল্যাটেনিং প্রত্যাশা করবেন না।

৪. বহু-শর্ত ফিল্টার: তুলনা, লজিক ও অস্তিত্ব

ফিল্টার [?(...)]-এ চার ধরনের গঠন থাকতে পারে: তুলনা, লজিক অপারেটর, অস্তিত্ব পরীক্ষা ও ফাংশন। একটি প্রচলিত বহু-শর্ত কোয়েরি এরকম:

$..book[?(@.price < 10 && @.stock)]

এর অর্থ "দাম ১০-এর নিচে এবং স্টক সত্য মানসম্পন্ন"। কয়েকটি সেমান্টিক্স বিবরণে মনোযোগ দিন:

  • @.stock অস্তিত্ব পরীক্ষা, "মান সত্য" নয়। ফিল্ড থাকলেও মান false হলে শর্ত তবু সত্য। বুলিয়ান মান পরীক্ষা করতে @.stock == true লিখতে হবে;
  • && ||-এর চেয়ে বেশি বাঁধে। মেশানোর সময় বন্ধনী যোগ করুন, স্মৃতির উপর ভরসা করবেন না;
  • তুলনার দুই পক্ষের টাইপ একই হতে হবে। সংখ্যা ও স্ট্রিং স্বয়ংক্রিয়ভাবে রূপান্তর হয় না; কঠোর বাস্তবায়নে @.price < "10" মিথ্যা বা এরর;
  • অনুপস্থিত ফিল্ড তুলনাকে সবসময় মিথ্যা করে। @.missing < 10 এরর দেয় না; কেবল কিছুই মেলে না।

ফিল্টার JavaScript-এর মতো লিখলে এখানেই পা পিছলে সবচেয়ে বেশি: JavaScript-এ if (obj.stock) truthiness পরীক্ষা করে, অথচ JSONPath অস্তিত্ব পরীক্ষা করে। সম্পূর্ণ স্ট্যান্ডার্ড সিনট্যাক্স ও ফাংশনের জন্য আবার পড়ুন JSONPath কোয়েরি ভাষা বাস্তবে।

৫. স্ক্রিপ্ট এক্সপ্রেশন: বেশি ক্ষমতা, কম পোর্টেবিলিটি

মূল গেসনার বাস্তবায়ন ও jsonpath-plus [?(@.price < $.max)]-এর মতো ক্রস-নোড তুলনা, এমনকি যেকোনো স্ক্রিপ্ট অনুমোদন করে। RFC 9535 স্পষ্টভাবে কেবল চলতি নোড @ অ্যাক্সেসের অনুমতি দেয় আর ফিল্টারে $ নিষিদ্ধ করে।

// Works in older implementations; not allowed by RFC 9535
$..book[?(@.price < $.expensive)]

// Standard approach: pass the threshold from the caller
query(document, '$..book[?(@.price < threshold)]', { threshold: 10 })

স্ক্রিপ্ট এক্সপ্রেশন তিনটি সমস্যা তৈরি করে:

  1. পোর্টেবিলিটি শূন্যে নামে। লাইব্রেরি বদলানো মানে প্রতিটি এক্সপ্রেশন আবার লেখা;
  2. নিরাপত্তা সীমানা উধাও হয়। এক্সপ্রেশন ব্যবহারকারীর কাছ থেকে এলে স্ক্রিপ্ট মূল্যায়ন কোড এক্সিকিউশন তুলে দেয়;
  3. স্ট্যাটিক অপ্টিমাইজেশন অসম্ভব হয়। বাস্তবায়ন কেবল নোড ধরে ধরে ব্যাখ্যা করতে পারে, যা ধীর ও ক্যাশ করা কঠিন।

সত্যিই ক্রস-নোড তুলনা দরকার হলে থ্রেশহোল্ড কোয়েরি প্যারামিটার হিসেবে দিন আর অ্যাপ্লিকেশন কোডে দ্বিতীয়বার ফিল্টার করুন। এটি সাধারণত এক্সটেনশন সিনট্যাক্সের উপর নির্ভর করার চেয়ে বেশি স্থিতিশীল।

৬. ফলের আকৃতি: আপনি মান ভাবেন, পান নোড

একই এক্সপ্রেশন লাইব্রেরিভেদে অন্তত তিন আকৃতি ফেরত দিতে পারে:

["JSON: The Definitive Guide", "How Parsers Work", "Streaming JSON in Practice"] // value array
[{ "path": "$['store']['book'][0]['title']", "value": "..." }]                 // path + value
[{ "pointer": "/store/book/0/title", "value": "..." }]                          // JSON Pointer + value

এটি সরাসরি তিনটি বিষয় প্রভাবিত করে: ফ্রন্টএন্ড কীভাবে ফল পড়ে, ফল কীভাবে ডুপ্লিকেটমুক্ত হয়, আর কোয়েরি ফল কীভাবে লেখার অপারেশনে বদলায়। RFC 9535-নির্ধারিত নোডলিস্ট নোড রেফারেন্সের সেট, কিন্তু JavaScript বাস্তবায়ন সাধারণত কেবল মান ফেরত দেয় কারণ রেফারেন্স প্রসেস সীমানা পার হতে পারে না।

ব্যবহারিক পরামর্শ:

  • একক মান সবসময় [0] বা value() দিয়ে পড়ুন; ফল স্কেলার ধরে নেবেন না;
  • ফেরত লিখতে হলে JSON Pointer ফেরত দেওয়া বাস্তবায়ন বাছুন, বা পয়েন্টার নিজে বানান;
  • খালি ফল ও [null] ফল আলাদা; truthiness নয়, length দেখুন।

৭. লাইব্রেরির পার্থক্য: মাইগ্রেশনের আগে কমপ্লায়েন্স স্যুট চালান

সক্ষমতা মূল গেসনার jsonpath-plus কঠোর RFC 9535
ফিল্টার বন্ধনী ?() বাধ্যতামূলক সামঞ্জস্যপূর্ণ ঐচ্ছিক
ক্রস-রুট রেফারেন্স $.x সমর্থিত সমর্থিত নিষিদ্ধ
স্ক্রিপ্ট এক্সপ্রেশন সমর্থিত সমর্থিত নিষিদ্ধ
ঋণাত্মক ইনডেক্স ও ধাপ সমর্থিত সমর্থিত সমর্থিত
পাথ ফেরত কনফিগারযোগ্য কনফিগারযোগ্য নির্ধারিত নয়
length()-এর মতো ফাংশন নেই এক্সটেনশন স্ট্যান্ডার্ড ফাংশন

মাইগ্রেশনের আগে অন্তত চারটি যাচাই করুন: বন্ধনী দরকার কি না, ফিল্টারে $ আসতে পারে কি না, ঋণাত্মক ধাপ কেমন আচরণ করে, আর ফল কাঠামো। অফিশিয়াল কমপ্লায়েন্স টেস্ট স্যুট বেশিরভাগ সিনট্যাক্স পার্থক্য ঢাকে আর "লাইব্রেরি বদলানোর পর তিন সারি উধাও" ধরনের নীরব ব্যর্থতা আটকায়।

৮. পারফরম্যান্স ও ভুল ব্যবহার চেকলিস্ট

পারফরম্যান্স এক বাক্যে: JSONPath পূর্ণ ট্রাভার্সাল, আর .. সবচেয়ে দামি ধরনের পূর্ণ ট্রাভার্সাল।

  • ১,০০,০০০-এর বেশি নোডযুক্ত ডকুমেন্টে আগে স্পষ্ট পাথ দিয়ে পরিধি সংকুচিত করুন, তারপর উপসেট ফিল্টার করুন;
  • এক্সপ্রেশন একবার কম্পাইল করে পুনরায় ব্যবহার করুন; লুপের ভেতরে স্ট্রিং আবার পার্স করবেন না;
  • অ্যাগ্রিগেশনে (যোগ, গ্রুপিং, সর্টিং) jq বা কোডে যান; JSONPath কেবল বাছাই করে;
  • শর্ত যত আগে সম্ভব বসান: $.store.book[?(@.price < 10)] $..[?(@.price < 10)]-এর চেয়ে অনেক কম অপ্রাসঙ্গিক নোড স্ক্যান করে।

ভুল ব্যবহার চেকলিস্ট:

  • [ ] অস্তিত্ব পরীক্ষাকে বুলিয়ান সত্য পরীক্ষা ধরা;
  • [ ] জানা গভীরতার বদলে $.. ব্যবহার;
  • [ ] ক্রস-নোড তুলনায় স্ক্রিপ্ট এক্সপ্রেশনের উপর নির্ভর;
  • [ ] ফল সবসময় মানের অ্যারে ধরে নেওয়া;
  • [ ] ব্যবহারকারী-নিয়ন্ত্রিত এক্সপ্রেশন দৈর্ঘ্য ও নেস্টিং সীমা ছাড়া অনুমোদন।

সাধারণ প্রশ্ন

ফিল্ড false হলেও @.stock মেলে কেন?

কারণ ফিল্টারে খালি পাথ মানে "ফিল্ড আছে", "মান সত্য" নয়। বুলিয়ান পরীক্ষা করতে @.stock == true দিয়ে স্পষ্টভাবে তুলনা করুন। JSONPath ও JavaScript truthiness-এর মধ্যে এটাই সবচেয়ে বড় সেমান্টিক পার্থক্য।

পুনরাবৃত্ত ডিসেন্টের ক্রম স্থিতিশীল?

না। RFC 9535 নোড-সেট সেমান্টিক্স নির্ধারণ করে, আর ট্রাভার্সাল ক্রম নির্ভর করে বাস্তবায়ন কীভাবে শিশু পরিদর্শন করে। নির্দিষ্ট ক্রম দরকার হলে অ্যারে লোকেট করে ইনডেক্স দিয়ে পড়ুন, বা অ্যাপ্লিকেশন কোডে ফল সাজান।

স্লাইস ও ফিল্টার মেলানো যায়?

হ্যাঁ, কিন্তু পরিধি মনে রাখুন। $.store.book[0:2][?(@.stock)] কেবল স্লাইসের উৎপন্ন দুই বই ফিল্টার করে। আগে ফিল্টার করে পরে স্লাইস করতে $.store.book[?(@.stock)][0:2] লিখুন; ভিন্ন ক্রমে ভিন্ন ফল।

স্ট্যান্ডার্ড নিষিদ্ধ করলেও jsonpath-plus $.expensive সমর্থন করে কেন?

কারণ ফিল্টার কেবল চলতি নোড @-এর নিরিখে সংজ্ঞায়িত। ক্রস-রুট রেফারেন্স এক্সপ্রেশনকে পুরো ডকুমেন্ট প্রসঙ্গের উপর নির্ভরশীল করে, যা স্ট্যাটিকভাবে বিশ্লেষণ ও ভাষাভেদে পোর্ট করা কঠিন। থ্রেশহোল্ড এক্সপ্রেশনে এম্বেড না করে প্যারামিটার হিসেবে দিন।

পুনরাবৃত্ত ডিসেন্ট কীভাবে অপ্রাসঙ্গিক নোড স্ক্যান করা থেকে বিরত রাখব?

গভীরতা জানলে স্পষ্ট পাথ লিখুন, পরিধি আগে সংকুচিত করুন, আর জানা স্তরের বদলে $.. ব্যবহার না করে কেবল উপসেট ফিল্টার করুন। শর্ত যত আগে সম্ভব বসান: $.store.book[?(@.price < 10)] $..[?(@.price < 10)]-এর চেয়ে অনেক কম অপ্রাসঙ্গিক নোড স্ক্যান করে। ১,০০,০০০-এর বেশি নোডযুক্ত ডকুমেন্টে আগে এটিই করুন।

তথ্যসূত্র

সংশ্লিষ্ট টুল

সম্পর্কিত নিবন্ধ

JSONPath কোয়েরি ভাষা বাস্তবে

২০২৪ সালে JSONPath অবশেষে আনুষ্ঠানিক স্ট্যান্ডার্ড পেল, RFC 9535। এই নিবন্ধে সিনট্যাক্স, ফিল্টার সেমান্টিক্স, ফাংশন ও বাস্তবায়নগুলোর ঐতিহাসিক পার্থক্য ব্যাখ্যা করা হয়েছে।

মধ্যবর্তী~12 মিনিট পড়াআপডেট 2026-10-30

JSON Pointer, Patch ও Merge Patch

তিনটি ছোট স্পেসিফিকেশন মিলে একটি পরিবর্তন প্রোটোকল: Pointer লোকেট করে, Patch সুনির্দিষ্টভাবে সম্পাদনা করে, Merge Patch আংশিক মার্জ করে। ভুল বাছাই অ্যারে ও সমবর্তীতায় ক্ষতি করে।

মধ্যবর্তী~12 মিনিট পড়াআপডেট 2026-10-30

JSONPath নাকি JSON Pointer

JSON Pointer হলো কি হিসেবে রাখা যায় এমন অনন্য ঠিকানা; JSONPath একটি কোয়েরি ভাষা। ভুলটি ব্যবহারে কনফিগ হালনাগাদ ভাঙে বা ভাঙা JSONPath নতুন করে বানাতে হয়।

মধ্যবর্তী~4 মিনিট পড়াআপডেট 2026-10-30