Ruby on Rails
ActiveRecord क्वेरी इंटरफ़ेस
खोज…
परिचय
ActiveRecord MVC में M है जो व्यापार डेटा और तर्क का प्रतिनिधित्व करने के लिए जिम्मेदार प्रणाली की परत है। तकनीक एक संबंधपरक डेटाबेस प्रबंधन प्रणाली में तालिकाओं के लिए एक आवेदन पत्र की समृद्ध वस्तुओं जोड़ता है हे bject आर elational एम apper (ORM) है।
ActiveRecord आपके लिए डेटाबेस पर क्वेरी करेगा और अधिकांश डेटाबेस सिस्टम के साथ संगत है। भले ही आप डेटाबेस प्रणाली का उपयोग कर रहे हों, ActiveRecord विधि प्रारूप हमेशा समान रहेगा।
।कहाँ पे
where
विधि किसी भी ActiveRecord
मॉडल पर उपलब्ध है और दिए गए मानदंड से मेल खाने वाले रिकॉर्ड के सेट के लिए डेटाबेस को क्वेरी करने की अनुमति देता है।
where
विधि एक हैश स्वीकार करता है जहाँ कुंजियाँ उस तालिका नाम के स्तंभ नामों से मेल खाती हैं जो मॉडल प्रस्तुत करता है।
एक सरल उदाहरण के रूप में, हम निम्नलिखित मॉडल का उपयोग करेंगे:
class Person < ActiveRecord::Base
#attribute :first_name, :string
#attribute :last_name, :string
end
Sven
के पहले नाम के साथ सभी लोगों को खोजने के लिए:
people = Person.where(first_name: 'Sven')
people.to_sql # "SELECT * FROM people WHERE first_name='Sven'"
Sven
के पहले नाम और Schrodinger
अंतिम नाम वाले सभी लोगों को खोजने के लिए:
people = Person.where(first_name: 'Sven', last_name: 'Schrodinger')
people.to_sql # "SELECT * FROM people WHERE first_name='Sven' AND last_name='Schrodinger'"
उपर्युक्त उदाहरण में, sql आउटपुट दिखाता है कि रिकॉर्ड केवल तभी लौटाया जाएगा जब first_name
और last_name
दोनों मेल खाते हों।
OR शर्त के साथ क्वेरी
first_name == 'Bruce'
या last_name == 'Wayne'
साथ रिकॉर्ड खोजने के लिए
User.where('first_name = ? or last_name = ?', 'Bruce', 'Wayne')
# SELECT "users".* FROM "users" WHERE (first_name = 'Bruce' or last_name = 'Wayne')
एक सरणी के साथ
where
किसी भी ActiveRecord मॉडल पर विधि का उपयोग फॉर्म के SQL को उत्पन्न करने के लिए किया जा सकता है WHERE column_name IN (a, b, c, ...)
। यह एक सरणी को तर्क के रूप में पारित करके प्राप्त किया जाता है।
एक सरल उदाहरण के रूप में, हम निम्नलिखित मॉडल का उपयोग करेंगे:
class Person < ActiveRecord::Base
#attribute :first_name, :string
#attribute :last_name, :string
end
people = Person.where(first_name: ['Mark', 'Mary'])
people.to_sql # "SELECT * FROM people WHERE first_name IN ('Mark', 'Mary')"
सरणी एक हैं, तो nil
, एसक्यूएल जांच करने के लिए संशोधित किया जाएगा यदि स्तंभ है null
:
people = Person.where(first_name: ['Mark', 'Mary', nil])
people.to_sql # "SELECT * FROM people WHERE first_name IN ('Mark', 'Mary') OR first_name IS NULL"
कार्यक्षेत्र
स्कोप्स ActiveRecord
मॉडल पर पूर्वनिर्धारित फ़िल्टर के रूप में कार्य करते हैं।
scope
क्लास पद्धति का उपयोग करके एक स्कोप परिभाषित किया गया है।
एक सरल उदाहरण के रूप में, हम निम्नलिखित मॉडल का उपयोग करेंगे:
class Person < ActiveRecord::Base
#attribute :first_name, :string
#attribute :last_name, :string
#attribute :age, :integer
# define a scope to get all people under 17
scope :minors, -> { where(age: 0..17) }
# define a scope to search a person by last name
scope :with_last_name, ->(name) { where(last_name: name) }
end
स्कोप को सीधे मॉडल क्लास से दूर बुलाया जा सकता है:
minors = Person.minors
स्कोप्स जंजीर हो सकते हैं:
peters_children = Person.minors.with_last_name('Peters')
where
विधि और अन्य क्वेरी प्रकार विधियों को भी जंजीर किया जा सकता है:
mary_smith = Person.with_last_name('Smith').where(first_name: 'Mary')
पर्दे के पीछे, एक मानक वर्ग विधि के लिए स्कोप बस सिंटैक्टिक चीनी हैं। उदाहरण के लिए, ये विधियां कार्यात्मक रूप से समान हैं:
scope :with_last_name, ->(name) { where(name: name) }
# This ^ is the same as this:
def self.with_last_name(name)
where(name: name)
end
डिफ़ॉल्ट स्कोप
मॉडल में सभी कार्यों के लिए एक डिफ़ॉल्ट गुंजाइश सेट करने के लिए अपने मॉडल में।
scope
मेथड और एक क्लास मेथड के बीच एक उल्लेखनीय अंतर है:scope
डिफाइन्ड स्कोप्स हमेशा एकActiveRecord::Relation
लौटाएंगे, भले ही रिटर्न के भीतर तर्क शून्य हो। वर्ग विधियाँ, हालांकि, ऐसा कोई सुरक्षा जाल नहीं है और यदि वे कुछ और लौटाते हैं तो श्रृंखलाबद्धता को तोड़ सकते हैं।
where.not
where
खंडों का उपयोग करके खंड को where.not
जा सकता है।
class Person < ApplicationRecord #attribute :first_name, :string end people = Person.where.not(first_name: ['Mark', 'Mary']) # => SELECT "people".* FROM "people" WHERE "people"."first_name" NOT IN ('Mark', 'Mary')
ActiveRecord द्वारा समर्थित 4.0 और बाद में।
आदेश
आप का उपयोग करके ActiveRecord क्वेरी परिणामों आदेश कर सकते हैं .order
:
User.order(:created_at)
#=> => [#<User id: 2, created_at: "2015-08-12 21:36:23">, #<User id: 11, created_at: "2015-08-15 10:21:48">]
यदि निर्दिष्ट नहीं है, तो आरोही क्रम में आदेश दिया जाएगा। आप इसे करके निर्दिष्ट कर सकते हैं:
User.order(created_at: :asc)
#=> => [#<User id: 2, created_at: "2015-08-12 21:36:23">, #<User id: 11, created_at: "2015-08-15 10:21:48">]
User.order(created_at: :desc)
#=> [#<User id: 7585, created_at: "2016-07-13 17:15:27">, #<User id: 7583, created_at: "2016-07-13 16:51:18">]
.order
भी एक स्ट्रिंग को स्वीकार करता है, इसलिए आप भी कर सकते हैं
User.order("created_at DESC")
#=> [#<User id: 7585, created_at: "2016-07-13 17:15:27">, #<User id: 7583, created_at: "2016-07-13 16:51:18">]
जैसा कि स्ट्रिंग कच्चा एसक्यूएल है, आप एक तालिका भी निर्दिष्ट कर सकते हैं और न केवल एक विशेषता। यह मानते हुए कि आप users
को उनकी role
नाम के अनुसार क्रम देना चाहते हैं, आप ऐसा कर सकते हैं:
Class User < ActiveRecord::Base
belongs_to :role
end
Class Role < ActiveRecord::Base
has_many :users
end
User.includes(:role).order("roles.name ASC")
order
गुंजाइश भी एक नोड नोड स्वीकार कर सकते हैं:
User.includes(:role).order(User.arel_table[:name].asc)
ActiveRecord बैंग (!) विधियाँ
यदि आपको विफलता के मामले में false
मूल्य के बजाय अपवाद जुटाने के लिए ActiveRecord विधि की आवश्यकता है, तो आप जोड़ सकते हैं !
उनको। यह बहुत महत्वपूर्ण है। यदि आप उपयोग नहीं करते हैं तो कुछ अपवादों / असफलताओं को पकड़ना मुश्किल है! उन पर। मैंने आपको अपने विकास चक्र में ऐसा करने की सलाह दी है ताकि आप अपना समय बचाने के लिए अपने सभी ActiveRecord कोड को इस तरह से लिख सकें।
Class User < ActiveRecord::Base
validates :last_name, presence: true
end
User.create!(first_name: "John")
#=> ActiveRecord::RecordInvalid: Validation failed: Last name can't be blank
ActiveRecord विधियाँ जो एक धमाके को स्वीकार करती हैं ( !
) हैं:
-
.create!
-
.take!
-
.first!
-
.last!
-
.find_by!
-
.find_or_create_by!
-
#save!
-
#update!
- सभी एआर गतिशील खोजक
.find_by
आप find_by
का उपयोग करके अपनी तालिका के किसी भी क्षेत्र के रिकॉर्ड पा सकते हैं।
इसलिए, यदि आपके पास एक User
मॉडल है जिसमें first_name
विशेषता है जो आप कर सकते हैं:
User.find_by(first_name: "John")
#=> #<User id: 2005, first_name: "John", last_name: "Smith">
ऐसा find_by
है कि find_by
डिफ़ॉल्ट रूप से कोई अपवाद नहीं फेंकता है। यदि परिणाम एक खाली सेट है, तो यह find
बजाय nil
लौटाता है।
यदि अपवाद की आवश्यकता है तो find_by!
उपयोग कर सकते हैं find_by!
कि एक को जन्म देती है ActiveRecord::RecordNotFound
तरह त्रुटि find
।
।सभी हटा दो
यदि आपको बहुत सारे रिकॉर्ड जल्दी से हटाने की आवश्यकता है, तो ActiveRecord .delete_all
विधि देता है। उस तालिका, या एक संग्रह के सभी रिकॉर्ड को हटाने के लिए, सीधे एक मॉडल पर बुलाया जाएगा। हालांकि सावधान रहें, क्योंकि .delete_all
किसी भी वस्तु को .delete_all
नहीं देता है इसलिए कोई कॉलबैक नहीं देता है ( before_*
और after_destroy
ट्रिगर नहीं होता है)।
User.delete_all
#=> 39 <-- .delete_all return the number of rows deleted
User.where(name: "John").delete_all
ActiveRecord केस असंवेदनशील खोज
यदि आपको समान मानों के लिए ActiveRecord मॉडल खोजने की आवश्यकता है, तो आपको LIKE
या ILIKE
का उपयोग करने के लिए लुभाया जा सकता है, लेकिन यह डेटाबेस इंजनों के बीच पोर्टेबल नहीं है। इसी तरह, हमेशा डाउनकास्टिंग या अपकमिंग का सहारा लेने से प्रदर्शन की समस्याएं पैदा हो सकती हैं।
आप ActiveRecord की अंतर्निहित Arel matches
विधि का उपयोग सुरक्षित तरीके से करने के लिए कर सकते हैं:
addresses = Address.arel_table
Address.where(addresses[:address].matches("%street%"))
Arel डेटाबेस इंजन को कॉन्फ़िगर करने के लिए उपयुक्त LIKE या ILIKE कंस्ट्रक्शन लागू करेगा।
पहला और अंतिम रिकॉर्ड प्राप्त करें
डेटाबेस से first
और last
रिकॉर्ड प्राप्त करने के लिए रेल के पास बहुत आसान तरीका है।
users
तालिका से first
रिकॉर्ड प्राप्त करने के लिए हमें निम्नलिखित कमांड टाइप करने की आवश्यकता है:
User.first
यह निम्नलिखित sql
क्वेरी उत्पन्न करेगा:
SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
और रिकॉर्ड के बाद वापस आ जाएगा:
#<User:0x007f8a6db09920 id: 1, first_name: foo, created_at: Thu, 16 Jun 2016 21:43:03 UTC +00:00, updated_at: Thu, 16 Jun 2016 21:43:03 UTC +00:00 >
users
तालिका से last
रिकॉर्ड प्राप्त करने के लिए हमें निम्नलिखित कमांड टाइप करने की आवश्यकता है:
User.last
यह निम्नलिखित sql
क्वेरी उत्पन्न करेगा:
SELECT `users`.* FROM `users` ORDER BY `users`.`id` DESC LIMIT 1
और रिकॉर्ड के बाद वापस आ जाएगा:
#<User:0x007f8a6db09920 id: 10, first_name: bar, created_at: Thu, 16 Jun 2016 21:43:03 UTC +00:00, updated_at: Thu, 16 Jun 2016 21:43:03 UTC +00:00 >
पहली और आखिरी विधि करने के लिए एक पूर्णांक पासिंग वस्तुओं की एक सीमा क्वेरी और रिटर्न सरणी पैदा करता है।
User.first(5)
यह निम्नलिखित sql
क्वेरी उत्पन्न करेगा।
SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 5
तथा
User.last(5)
यह निम्नलिखित sql
क्वेरी उत्पन्न करेगा।
SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 5
.group और .count
हमारे पास एक Product
मॉडल है और हम उन्हें उनकी category
अनुसार समूह बनाना चाहते हैं।
Product.select(:category).group(:category)
यह डेटाबेस को निम्नानुसार क्वेरी करेगा:
SELECT "product"."category" FROM "product" GROUP BY "product"."category"
सुनिश्चित करें कि समूहीकृत फ़ील्ड भी चयनित है। समूहन - विशेष रूप से घटना की गणना के लिए - इस मामले में - categories
लिए उपयोगी है।
Product.select(:category).group(:category).count
जैसा कि क्वेरी से पता चलता है, यह गिनती के लिए डेटाबेस का उपयोग करेगा, जो पहले रिकॉर्ड को प्राप्त करने और कोड में गिनती करने की तुलना में बहुत अधिक कुशल है:
SELECT COUNT("products"."category") AS count_categories, "products"."category" AS products_category FROM "products" GROUP BY "products"."category"
डीडीस्टिंक्ट (या। क्यूनीक)
यदि आप किसी परिणाम से डुप्लिकेट हटाना चाहते हैं, तो आप .distinct()
उपयोग कर सकते हैं:
Customers.select(:country).distinct
यह डेटाबेस पर निम्नानुसार प्रश्न करता है:
SELECT DISTINCT "customers"."country" FROM "customers"
.uniq()
का समान प्रभाव है। रेल 5.0 के साथ यह पदावनत हो गया और इसे 5.1 संस्करण के साथ रेल से हटा दिया जाएगा। इसका कारण यह है, unique
शब्द का अलग अर्थ नहीं है और यह भ्रामक हो सकता है। इसके अलावा distinct
SQL सिंटैक्स के करीब है।
में शामिल
joins()
आपको अपने वर्तमान मॉडल में तालिकाओं में शामिल होने की अनुमति देता है। पूर्व के लिए।
User.joins(:posts)
निम्न SQL क्वेरी का उत्पादन करेगा:
"SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id""
तालिका में शामिल होने के बाद, आपको इसकी पहुँच प्राप्त होगी:
User.joins(:posts).where(posts: { title: "Hello world" })
बहुवचन रूप पर ध्यान दें। यदि आपका संबंध है :has_many
, तो :has_many
joins()
तर्क बहुवचन होना चाहिए। अन्यथा, एकवचन का उपयोग करें।
नेस्टेड joins
:
User.joins(posts: :images).where(images: { caption: 'First post' })
जो उत्पादन करेगा:
"SELECT "users".* FROM "users" INNER JOIN "posts" ON "posts"."user_id" = "users"."id" INNER JOIN "images" ON "images"."post_id" = "images"."id""
शामिल
ActiveRecord के साथ यह सुनिश्चित करना includes
कि सभी निर्दिष्ट संघों को कम से कम प्रश्नों की संभावित संख्या का उपयोग करके लोड किया जाए। इसलिए जब किसी संबंधित तालिका के साथ डेटा के लिए एक तालिका को क्वेरी करते हैं, तो दोनों तालिकाओं को मेमोरी में लोड किया जाता है।
@authors = Author.includes(:books).where(books: { bestseller: true } )
# this will print results without additional db hitting
@authors.each do |author|
author.books.each do |book|
puts book.title
end
end
Author.joins(:books).where(books: { bestseller: true } )
केवल लेखकों को लोडिंग पुस्तकों के बिना स्मृति में शर्तों के साथ लोड करेगी। नेस्टेड एसोसिएशन के बारे में अतिरिक्त जानकारी की आवश्यकता नहीं होने पर joins
उपयोग करें।
@authors = Author.joins(:books).where(books: { bestseller: true } )
# this will print results without additional queries
@authors.each { |author| puts author.name }
# this will print results with additional db queries
@authors.each do |author|
author.books.each do |book|
puts book.title
end
end
सीमा और ऑफसेट
आप रिकॉर्ड किए जाने वाले रिकॉर्ड की संख्या बताने के लिए limit
का उपयोग कर सकते हैं, और रिकॉर्ड वापस करने के लिए शुरू करने से पहले छोड़ने के लिए रिकॉर्ड की संख्या बताने के लिए offset
का उपयोग कर सकते हैं।
उदाहरण के लिए
User.limit(3) #returns first three records
यह निम्नलिखित sql क्वेरी उत्पन्न करेगा।
"SELECT `users`.* FROM `users` LIMIT 3"
जैसा कि उपरोक्त क्वेरी में ऑफसेट का उल्लेख नहीं किया गया है, इसलिए यह पहले तीन रिकॉर्ड लौटाएगा।
User.limit(5).offset(30) #returns 5 records starting from 31th i.e from 31 to 35
यह निम्नलिखित sql क्वेरी उत्पन्न करेगा।
"SELECT `users`.* FROM `users` LIMIT 5 OFFSET 30"