क्वेरी और वैलिडेशन FAQ: JSONPath और Schema
मुख्य बात: पाथ क्वेरी में JSONPath उपयोग करें या Pointer, Patch और Merge Patch में कैसे चुनें, Schema क्या रोक सकता है, और ड्राफ़्ट संस्करण कैसे चुनें — सब एक ही बार में समझाया गया।

मुख्य बात: शर्त के आधार पर नोड ढूँढने के लिए JSONPath, सटीक स्थानों को संबोधित करने और संपादित करने के लिए JSON Pointer या JSON Patch, और कॉन्फ़िग मिलाने के लिए Merge Patch उपयोग करें; नए Schema को 2020-12 पर पिन करें और allErrors चालू करें ताकि हर विफलता एक ही बार में वापस आए।
क्वेरी का अर्थ है "इसे ढूँढो"; वैलिडेशन का अर्थ है "पुष्टि करो कि यह सही है"। हर एक का अपना मानक है, इसलिए इन्हें मिलाएँ नहीं।
1. पाथ क्वेरी
JSONPath और JSON Pointer में कैसे चुनूँ?
यह इस पर निर्भर करता है कि आप "शर्त से ढूँढ रहे हैं" या "स्थिति से प्राप्त कर रहे हैं"।
| आयाम | JSONPath | JSON Pointer |
|---|---|---|
| मानक | RFC 9535 (2024) | RFC 6901 (2013) |
| एक्सप्रेशन | $.users[?(@.age > 18)].id |
/users/0/id |
| वाइल्डकार्ड और रिकर्शन | *, .. का समर्थन |
समर्थित नहीं |
| शर्त-आधारित फ़िल्टरिंग | समर्थित | समर्थित नहीं |
| परिणाम | नोड सेट (कई भी हो सकते हैं) | एक ही स्थान |
| अभिव्यक्ति शक्ति | मजबूत, लेकिन कार्यान्वयन भिन्नताओं का भारी विरासत | कमज़ोर, लेकिन पूरी तरह नियतात्मक |
| सामान्य उपयोग | लॉग निष्कर्षण, डीबगिंग, डेटा अन्वेषण | JSON Patch, कॉन्फ़िग एड्रेसिंग, एरर पाथ |
चयन नियम सीधा है:
- "किसी शर्त से मेल खाने वाले सभी नोड प्राप्त करने" हैं → JSONPath;
- "एक सटीक स्थान पिन करके उसे जोड़ना, हटाना या बदलना" है → JSON Pointer;
- दोनों साथ उपयोग करें: JSONPath से नोड ढूँढें और Pointer से उसका स्थान बताएँ।
API कॉन्ट्रैक्ट में एड्रेसिंग के लिए JSONPath उपयोग न करें। JSONPath एक सेट लौटाता है, और खाली, एक-तत्व, और बहु-तत्व परिणामों की तीन शाखाएँ प्रोटोकॉल को जटिल बना देती हैं; Pointer का अर्थ है "या तो यह किसी मौजूदा स्थान की ओर इंगित करता है या मौजूद नहीं है", जो कॉन्ट्रैक्ट के लिए अधिक उपयुक्त है।
$.. और $.* में क्या अंतर है?
$.. रिकर्शन डिसेंट है और हर स्तर पर चलता है; $.* केवल वर्तमान स्तर के सीधे बच्चे लौटाता है।
{
"a": { "id": 1, "child": { "id": 2 } },
"b": { "id": 3 }
}
$.*→ दो ऑब्जेक्ट{id:1, child:{...}}और{id:3};$..id→ तीन मान:1,2,3;$.*.id→1और3, नेस्टेड2को छोड़कर।
रिकर्शन डिसेंट सुविधाजनक है लेकिन महँगा: $.. पूरे tree पर चलता है, जो बड़े दस्तावेज़ पर O(n) है, और यह आसानी से उन गहरे फ़ील्ड को भी उठा लेता है जो आपका इरादा नहीं था।
अगर कोई ठोस स्तर काम करता है, तो .. से बचें।
क्या फ़िल्टर स्ट्रिंग की तुलना कर सकते हैं? क्या regex से मिला सकते हैं?
स्ट्रिंग तुलना काम करती है; regex कार्यान्वयन पर निर्भर करता है।
मानक सिंटैक्स (RFC 9535):
$.items[?(@.status == "active")]
$.items[?(@.price > 10 && @.stock > 0)]
$.items[?(@.name == $.target)] // compare with another node
स्ट्रिंग तुलना डबल कोट्स उपयोग करती है (RFC 9535 में सिंगल कोट्स की भी अनुमति है, लेकिन कुछ पुराने कार्यान्वयन केवल डबल कोट्स स्वीकार करते हैं)।
संख्यात्मक तुलना संख्यात्मक अर्थ का पालन करती है; स्ट्रिंग को संख्या के साथ मिलाना, जैसे "10" > 9, मानक में अपरिभाषित व्यवहार है, इसलिए इस पर निर्भर न रहें।
regex के लिए, RFC 9535 match() और search() फ़ंक्शन परिभाषित करता है, लेकिन कार्यान्वयनों के बीच उनका समर्थन काफ़ी भिन्न है।
सुरक्षित तरीका: JSONPath को मोटी फ़िल्टरिंग करने दें, और परिणाम प्राप्त करने के बाद कोड में regex मिलान करें।
JSON Patch या Merge Patch उपयोग करूँ?
दोनों "कुछ कैसे बदलना है" बताते हैं, लेकिन उनकी अभिव्यक्ति शक्ति और अर्थ पूरी तरह अलग हैं।
| आयाम | JSON Patch (RFC 6902) | Merge Patch (RFC 7386) |
|---|---|---|
| रूप | ऑपरेशनों का array [{"op":"add",...}] |
आंशिक ऑब्जेक्ट |
| समर्थित ऑपरेशन | add / remove / replace / move / copy / test | केवल merge (null से हटाना) |
| array तत्वों को संबोधित कर सकता है | हाँ, इंडेक्स से | नहीं, पूरा array बदल दिया जाता है |
| परमाणुता | test ऑप्टिमिस्टिक लॉकिंग सक्षम करता है |
कोई नहीं |
| दस्तावेज़ आकार | बड़ा लेकिन सटीक | छोटा लेकिन अभिव्यक्ति सीमित |
| किसके लिए अच्छा | बारीक संपादन, आंशिक API अपडेट | कॉन्फ़िग मिलाना, आंशिक फ़ॉर्म सबमिशन |
निर्णय मानदंड:
- array के तीसरे तत्व का कोई फ़ील्ड बदलना है → JSON Patch;
- कई कॉन्फ़िग प्रविष्टियाँ मौजूदा कॉन्फ़िग में मिलानी हैं → Merge Patch;
- "अगर मूल मान X नहीं है तो विफल करो" वाला समवर्ती नियंत्रण चाहिए → JSON Patch का
test।
Merge Patch के null अर्थ का जाल ध्यान दें: null का अर्थ "इस कुंजी को हटाओ" है, न कि "मान को null करो"।
Merge Patch से किसी मान को null करना असंभव है।
2. Schema वैलिडेशन
JSON Schema कौन-सी समस्याएँ हल करता है?
यह "डेटा कैसा दिखना चाहिए" को मौखिक समझौते से मशीन-जाँचने योग्य कॉन्ट्रैक्ट में बदल देता है। जिन एरर को यह वास्तव में रोक सकता है:
- आवश्यक फ़ील्ड गायब (
required); - गलत टाइप, उदाहरण के लिए जहाँ संख्या अपेक्षित थी वहाँ string (
type); - सीमा से बाहर मान (
minimum/maximum/minLength); - अनुमत सेट से बाहर मान (
enum); - असंगत array तत्व टाइप या गलत array लंबाई (
items/minItems); - नेस्टेड संरचनाओं में गायब फ़ील्ड (
propertiesके माध्यम से रिकर्शन वैलिडेशन); - अतिरिक्त फ़ील्ड (
additionalProperties: false).
जिन्हें यह नहीं हल कर सकता: व्यावसायिक नियम ("समाप्ति समय शुरू के समय से बाद होना चाहिए"), क्रॉस-फ़ील्ड शर्तें (कुछ if/then से व्यक्त की जा सकती हैं,
लेकिन पठनीयता बिगड़ती है), डेटाबेस विशिष्टता, और अनुमति जाँच।
इसलिए Schema "डेटा आकार" का द्वारपाल है, व्यावसायिक तर्क का विकल्प नहीं।
draft-07 या 2020-12 उपयोग करूँ?
नए प्रोजेक्ट के लिए 2020-12 उपयोग करें; मौजूदा सिस्टम के लिए जाँचें कि वैलिडेटर क्या समर्थन करता है।
| संस्करण | स्थिति | मुख्य परिवर्तन |
|---|---|---|
| draft-04 | पुराना | कई पुरानी लाइब्रेरी अब भी इसे डिफ़ॉल्ट मानती हैं |
| draft-07 | वास्तविक मानक | सबसे व्यापक समर्थन, सबसे समृद्ध पारिस्थितिकी |
| 2019-09 | संक्रमणकालीन | $defs, unevaluatedProperties पेश किए |
| 2020-12 | वर्तमान में अनुशंसित | items को prefixItems + items में विभाजित किया, $dynamicRef समर्थित |
दो माइग्रेशन जाल:
- Tuple सिंटैक्स बदला: draft-07 में array-मान वाला
itemstuple व्यक्त करता था; 2020-12 ने उसेprefixItemsमें स्थानांतरित कर दिया; $refऔर सहोदर कीवर्ड: draft-07 में$refमौजूद होने पर सहोदर कीवर्ड अनदेखे किए जाते हैं; 2020-12 उन्हें साथ रहने देता है।
अगर वैलिडेटर केवल draft-07 समर्थित करता है, तो 2020-12 सिंटैक्स लिखने पर भी वह चुपचाप अनदेखा किया जाएगा — और सबसे खतरनाक स्थिति है "वैलिडेशन पास" जब कुछ भी वैलिडेट ही नहीं हुआ।
Schema से TypeScript टाइप कैसे जनरेट करूँ?
दो रास्ते: Schema से टाइप निकालना, या टाइप से Schema जनरेट करना।
Schema से टाइप की ओर (बैकएंड कॉन्ट्रैक्ट परिभाषित करता है, फ़्रंटएंड उसका उपभोग करता है):
import type { FromSchema } from 'json-schema-to-ts';
const userSchema = {
type: 'object',
properties: {
id: { type: 'string' },
age: { type: 'integer' },
},
required: ['id'],
additionalProperties: false,
} as const;
type User = FromSchema<typeof userSchema>;
// { id: string; age?: number }
कुंजी as const है: इसके बिना, type: 'string' को string के रूप में अनुमानित किया जाता है, लिटरल 'string' के रूप में नहीं, और अनुमान टूट जाता है।
टाइप से Schema की ओर (फ़्रंटएंड के पास पहले से टाइप हैं और रनटाइम वैलिडेशन चाहिए):
import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';
const userSchema = z.object({ id: z.string(), age: z.number().int().optional() });
const jsonSchema = zodToJsonSchema(userSchema);
इस रास्ते का लाभ यह है कि "एक परिभाषा से टाइप और रनटाइम वैलिडेशन दोनों मिलते हैं"; कीमत है एक DSL शामिल करना,
और जनरेट किया गया Schema कार्यान्वयन विवरण ले सकता है (उदाहरण के लिए एक भद्दी $ref संरचना)।
वैलिडेशन विफल होने पर विशिष्ट फ़ील्ड कैसे ढूँढूँ?
वैलिडेटर द्वारा लौटाए गए instancePath (2020-12) या dataPath (draft-07) को देखें; यह एरर स्थान की ओर इंगित करने वाला JSON Pointer है।
[
{
"instancePath": "/items/2/price",
"schemaPath": "#/properties/items/items/properties/price/type",
"keyword": "type",
"message": "must be number"
}
]
instancePath: "/items/2/price" सीधे बताता है: items array के तीसरे तत्व के price फ़ील्ड का टाइप गलत है।
दो व्यावहारिक सुझाव:
- सारे एरर एक साथ लौटाएँ पहले पर ही throw करने के बजाय — फ़्रंटएंड द्वारा एक ही बार में सब ठीक करना आगे-पीछे के प्रयासों से तेज़ होता है;
- अंतिम उपयोगकर्ताओं को दिखाने से पहले Pointer को सरल भाषा में बदलें;
/items/2/priceडेवलपर के लिए उपयोगी है और उपयोगकर्ता के लिए बेकार।
allErrors: true अधिकांश वैलिडेटर में स्विच है (Ajv में इसे स्पष्ट रूप से चालू करना पड़ता है); डिफ़ॉल्ट अक्सर fail-fast मोड होता है।
क्या additionalProperties: false चालू करना चाहिए?
आंतरिक कॉन्ट्रैक्ट के लिए चालू करें; सार्वजनिक API के साथ सतर्क रहें।
चालू होने पर, properties के अंतर्गत घोषित न की गई कोई भी फ़ील्ड वैलिडेशन विफल कर देती है। लाभ है टाइपो पकड़ना
(userNmae) और अप्रत्याशित पास-थ्रू; नुकसान है कि अपस्ट्रीम द्वारा फ़ील्ड जोड़ने से डाउनस्ट्रीम उपभोक्ता टूट जाते हैं, जिससे बैकवर्ड संगतता नष्ट होती है।
समझौता:
| परिदृश्य | सिफ़ारिश |
|---|---|
| आंतरिक सेवाओं के बीच | चालू करें। फ़ील्ड परिवर्तन संस्करण प्रबंधन से गुज़रें |
| सार्वजनिक बाहरी API | बंद रखें। अपस्ट्रीम को फ़ील्ड जोड़ने दें |
| थर्ड-पार्टी डेटा उपभोग करना | बंद रखें। दूसरी ओर आपके नियंत्रण में नहीं है |
| कॉन्फ़िग वैलिडेशन | चालू करें। कॉन्फ़िग में टाइपो तुरंत विफल होना चाहिए |
array तत्वों के अद्वितीय होने का वैलिडेशन कैसे करूँ?
दो अलग अर्थ — इन्हें न मिलाएँ:
{ "uniqueItems": true }
यह पूरे तत्व को डुप्लिकेट-मुक्त करता है, यानी array में दो गहराई से समान तत्व नहीं होने चाहिए।
{
"type": "array",
"items": { "type": "object", "properties": { "id": { "type": "string" } } },
"uniqueItems": true
}
ऊपर का स्निपेट केवल यह गारंटी देता है कि ऑब्जेक्ट समग्र रूप से डुप्लिकेट नहीं हैं; {"id":"a","name":"x"} और {"id":"a","name":"y"} डुप्लिकेट नहीं माने जाते।
किसी विशिष्ट फ़ील्ड से डुप्लिकेट हटाना है, तो Schema इसे व्यक्त नहीं कर सकता; आपको व्यावसायिक परत में वैलिडेट करना होगा:
const ids = items.map((item) => item.id);
if (new Set(ids).size !== ids.length) {
throw new Error('id 重复');
}
क्या format वाकई email और date वैलिडेट करता है?
ज़रूरी नहीं। स्पेसिफिकेशन में format डिफ़ॉल्ट रूप से "annotation" है, "assertion" नहीं, इसलिए वैलिडेटर इसे इकट्ठा कर सकता है बिना वैलिडेट किए।
- Ajv के लिए अलग
ajv-formatsपैकेज इंस्टॉल और कॉन्फ़िगर करना पड़ता है, वरनाformat: "email"लगभग निष्क्रिय है; - कुछ वैलिडेटर
formatको डिफ़ॉल्ट रूप से सक्षम assertion मानते हैं, इसलिए व्यवहार असंगत है; - सक्षम होने पर भी,
emailregex बहुत ढीला है —a@bपास हो जाता है।
निष्कर्ष: format को मजबूत वैलिडेशन न मानें। email, URL और date का सख्त वैलिडेशन अपने व्यावसायिक कोड में करें;
Schema में format को दस्तावेज़ीकरण के रूप में रखना फ़ायदेमंद है, लेकिन यह गंदे डेटा को रोकेगा ऐसी उम्मीद न रखें।
3. त्वरित संदर्भ
| प्रश्न | निष्कर्ष |
|---|---|
| शर्त से नोड ढूँढना | JSONPath |
| सटीक एड्रेसिंग, patch लागू करना | JSON Pointer |
| array तत्व बदलना | JSON Patch, Merge Patch यह नहीं कर सकता |
| कॉन्फ़िग मिलाना | Merge Patch |
| नए प्रोजेक्ट के लिए Schema संस्करण | 2020-12, prefixItems का ध्यान रखें |
| Schema से TS टाइप जनरेट करना | json-schema-to-ts + as const |
| वैलिडेशन एरर ढूँढना | instancePath पढ़ें, allErrors चालू करें |
| फ़ील्ड से डुप्लिकेट हटाना | Schema नहीं कर सकता; व्यावसायिक परत में Set उपयोग करें |
format: email |
अधिकांश वैलिडेटर डिफ़ॉल्ट रूप से इसे जाँचते नहीं, इसलिए इस पर निर्भर न रहें |