Knex: إضافة قدرة نوع upert

تم إنشاؤها على ٣٠ أغسطس ٢٠١٣  ·  54تعليقات  ·  مصدر: knex/knex

نشأت عن طريق adamscybot في tgriesser / رف الكتب رقم 55 - قد تكون هذه ميزة رائعة لإضافتها.

feature request

التعليق الأكثر فائدة

NicolajKN لا يجب عليك استخدام toString () ، فقد يتسبب ذلك في العديد من المشاكل ولن يمرر القيم من خلال الارتباطات إلى DB (ثقب أمان محتمل لحقن SQL).

نفس الشيء الذي تم القيام به بشكل صحيح سيكون كالتالي:

const query = knex('account').insert(accounts);
const safeQuery = knex.raw('? ON CONFLICT DO NOTHING', [query]);

ال 54 كومينتر

أوافق ، هذه _يمكن أن تكون ميزة لطيفة!

: +1:

: +1:

أقوم باستيراد بعض البيانات من ملف CSV وهناك فرصة جيدة لأن تتداخل بعض السجلات مع آخر استيراد (على سبيل المثال ، تم استيراد آخر مرة من 1 يناير إلى 31 مايو ، ويتم الاستيراد هذه المرة من 31 مايو إلى 18 يونيو).

لحسن الحظ ، يقوم نظام الطرف الثالث بتعيين معرفات فريدة بشكل موثوق.

ما هي أفضل طريقة لإدخال السجلات الجديدة وتحديث القديم؟

لم أجربه بعد ، لكنني كنت أفكر أنه سيكون شيئًا كهذا:

var ids = records.map(function (json) { return json.id })
  ;

Records.forge(ids).fetchAll().then(function () {
  records.forEach(function (record) {
    // now the existing records are loaded in the collection ?
    Object.keys(record).forEach(function (key) {
      Records.forge(record.id).set(key, record[key]);
    });
  });
  Records.invokeThen('save').then(function () {
    console.log('Records have been either inserted or updated');
  });
});

أيضًا ، في بعض الأحيان يتم تخزين الشيء الذي أقوم بتخزينه بواسطة قيمة معرّف محددة ، مثل التجزئة. في هذه الحالات ، أريد فقط إضافة البيانات أو استبدالها.

لا أستخدم SQL دائمًا على أنها SQL تقليدية. غالبًا ما أستخدمه باعتباره NoSQL مختلطًا مع الاستفادة من خرائط وفهارس واضحة للعلاقة.

: +1:

مرحبا،
هل هناك أخبار عن هذه الميزة الجديدة؟

أو هل يمكن لشخص أن يوصي بأمثلة توضح كيفية محاكاة هذه الوظيفة لـ mysql؟

شكرا

في الوقت الحالي ، أفعل ذلك باستخدام raw ، لكنني أعمل بجد لتوفير هذا هنا قريبًا.

نفذت Postgres للتو دعم upert بالمناسبة: +1:

http://git.postgresql.org/gitweb/؟p=postgresql.git؛a=commit؛h=168d5805e4c08bed7b95d351bf097cff7c07dd65

https://news.ycombinator.com/item؟id=9509870

بناء الجملة هو INSERT ... ON CONFLICT DO UPDATE

كنت أبحث عن طريقة للقيام بـ REPLACE INTO في MySql ووجدت طلب الميزة هذا. نظرًا لأن REPLACE و INSERT لهما نفس الصيغة تمامًا في MySql ، أتخيل أنه سيكون أسهل في التنفيذ من ON DUPLICATE KEY UPDATE . هل هناك أي خطط لتنفيذ REPLACE ؟ هل ستكون العلاقات العامة شيئًا ذا قيمة؟

أي تحديثات على هذا ، خاصة مع PostreSQL 9.5؟

أعتقد أن أحد الأسئلة المهمة هو ما إذا كان سيتم الكشف عن نفس توقيع الأسلوب upsert لهجات مختلفة ، مثل PostgreSQL و MySQL أم لا. في Sequelize ، أثيرت مشكلة تتعلق بقيمة الإرجاع upsert : https://github.com/sequelize/sequelize/issues/3354.

أدركت أن بعض طرق مكتبة KnexJS لها اختلافات فيما يتعلق بقيم الإرجاع في سياق اللهجات المختلفة (مثل insert ، حيث يتم إرجاع مصفوفة من المعرف الأول المُدرج لـ Sqlite و MySQL ، بينما مصفوفة من الكل يتم إرجاع المعرف المدرج مع PostgreSQL).

وفقًا للوثائق ، فإن بناء الجملة INSERT ... ON DUPLICATE KEY UPDATE في MySQL له السلوك التالي (http://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html):

باستخدام ON DUPLICATE KEY UPDATE ، تكون قيمة الصفوف المتأثرة لكل صف هي 1 إذا تم إدراج الصف كصف جديد ، و 2 إذا تم تحديث صف موجود ، و 0 إذا تم تعيين صف موجود على قيمه الحالية.

أثناء التواجد في PostgreSQL (http://www.postgresql.org/docs/9.5/static/sql-insert.html):

عند الإكمال الناجح ، يقوم الأمر INSERT بإرجاع علامة الأمر الخاصة بالنموذج

INSERT oid count

العدد هو عدد الصفوف التي تم إدراجها أو تحديثها. إذا كان العدد واحدًا بالضبط ، وكان الجدول الهدف يحتوي على معرفات OID ، فإن OID هو معرف الكائن المعين للصف المدرج. يجب أن يكون الصف الفردي قد تم إدراجه بدلاً من تحديثه. خلاف ذلك Oid هو صفر.

إذا كان الأمر INSERT يحتوي على عبارة RETURNING ، فستكون النتيجة مماثلة لتلك الخاصة بعبارة SELECT التي تحتوي على الأعمدة والقيم المحددة في قائمة RETURNING ، المحسوبة على الصف (الصفوف) التي تم إدراجها أو تحديثها بواسطة الأمر.

في هذه الحالة ، يمكن تغيير قيم الإرجاع بعبارة RETURNING .

أفكار؟

أنا قرد مصححة Client_PG لإضافة طريقة "onConflict" للإدراج. لنفترض أننا نريد زيادة بيانات اعتماد github oauth ، يمكننا كتابة الاستعلام كما يلي:

const profile = {
    access_token: "blah blah",
    username: "foobar",
    // ... etc
  }

  const oauth = {
    uid: "13344398",
    provider: "github",
    created_at: new Date(),
    updated_at: new Date(),
    info: profile,
  };

  // todo: add a "timestamp" method

const insert = knex("oauths").insert(oauth).onConflict(["provider", "uid"],{
  info: profile,
  updated_at: new Date(),
});

console.log(insert.toString())

تحدد مصفوفة أسماء الأعمدة قيد التفرد.

insert into "authentications" ("created_at", "info", "provider", "uid", "updated_at") values ('2016-02-14T14:42:18.342+08:00', '{\"access_token\":\"blah blah\",\"username\":\"foobar\"}', 'github', '13344398', '2016-02-14T14:42:18.342+08:00') on conflict ("provider", "uid")  do update set "info" = '{\"access_token\":\"blah blah\",\"username\":\"foobar\"}', "updated_at" = '2016-02-14T14:42:18.343+08:00'

انظر المضمون: https://gist.github.com/hayeah/1c8d642df5cfeabc2a5b للحصول على رقعة القرد.

هذه تجربة فائقة الاختراق ... لذلك لا تقم بالضبط بنسخ ولصق رقعة القرد في كود الإنتاج الخاص بك: p

المشاكل المعروفة:

  • تصحيح القرد موجود في QueryBuilder ويؤثر على جميع اللهجات ، لأن Client_PG لا يتخصص في المنشئ.
  • لا يدعم التحديث الأولي مثل count = count + 1
  • ربما يجب طرح onConflict إذا لم يتم إدراج أسلوب الاستعلام.

تعليق؟

hayeah أحب أسلوبك وهو يناسب Postgres. سأقوم بتجربة رقعة القرد الخاصة بك في مشروع ما لمعرفة ما إذا كان بإمكاني اكتشاف أي مشكلات بشكل تجريبي بخلاف تلك التي أشرت إليها.

اقتراح بناء الجملة: knex('table').upsert(['col1','col2']).insert({...}).update({...}); حيث سيأخذ upsert في بيان الحالة. بهذه الطريقة ليست محددة ديسيبل.

يمكن العثور على ملخص لعمليات التنفيذ المختلفة لعمليات التنشيط على https://en.wikipedia.org/wiki/Merge_ (SQL)

أنا مهتم بالحصول على هذه القدرة أيضًا. حالة الاستخدام: بناء نظام يعتمد على الكثير من البيانات الخارجية من خدمة خارجية ؛ أقوم باستقصاء بشكل دوري عن البيانات التي أحفظها في MySQL db محلي. من المحتمل أن تستخدم knex.raw في الوقت الحالي.

مهتم أيضًا ، ولكن في حالة الاستخدام الخاصة بي ، يجب أن يعمل بطريقة لا تستند إلى التعارضات ، حيث لا تحتوي الأعمدة دائمًا على قيود "فريدة" - ما عليك سوى تحديث الإدخالات التي تطابق الاستعلام إذا كانت موجودة ، وإلا أدخل صفوف جديدة.

haywirez أشعر بالفضول لمعرفة سبب عدم وجود قيود فريدة؟ ألن تتعرض لظروف العرق؟

hayeah لدي حالة استخدام محددة مع البيانات ذات الإطارات الزمنية ، وتخزين الإدخالات التي لها قيمة مرتبطة بيوم معين. لذلك أقوم بإدخال وتحديث الإدخالات التي تحتوي على "مفتاح مدمج" للطابع الزمني المطابق (اليوم) ، ومعرفين آخرين يتوافقان مع PK في جداول أخرى. في غضون 24 ساعة ، يتعين علي إما إدراجها أو تحديثها بأحدث التهم.

ستكون هذه ميزة رائعة!

مرحبا كل من علق هنا من أي وقت مضى. أنا أقوم بإضافة العلاقات العامة الرجاء التسمية.

يسعدني الحصول على علاقات عامة تضيف هذه الوظيفة ، لكني أود أن أرى مناقشة حول واجهة برمجة التطبيقات المطلوبة هنا أولاً.

ملاحظة.

^ متفق عليه.

سأقوم بحذف مثل هذه التعليقات ، إذا كنت ترغب في إضافة +1 ، فافعل ذلك مع القليل من رد فعل الرموز التعبيرية.

لدي مشكلة صغيرة في مجموعة قيود الأعمدة كما في أمثلةwillfarrell و hayeah . لست متأكدًا مما إذا كانت هذه الأمثلة يمكن أن تدعم خصائص json . هل هناك سبب لعدم تضمين أي من هذه المقترحات العبارات / "الاستفسارات" المناسبة لمطابقة السجل؟

اقتراح 1

knex('table')
  .where('id', '=', data.id)
  .upsert(data)

اقتراح 2

knex('table')
  .upsertQuery(knex => {
    return knex('table')
      .where('id', '=', data.id)
  })
  .upsertUpdate(knex => {
    return knex('table')
      .insert(data)
  })

اقتراح 3

knex('table')
  .where('id', '=', data.id)
  .insert(data)
  .upsert() // or .onConflictDoUpdate()

أنا أميل أكثر نحو شيء مثل 3.

فقط لإضافة هنا كيف mongodb يفعل ذلك .

db.collection.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   }
)

reggi أعتقد أن رقعة القرد الخاصة بي متوافقة مع where ...

reggi لا أرى وجهة نظرك.
هل يمكنك توضيح المزيد حول الوظيفة المفقودة من الأسلوب المقترح في أمثلةwillfarrell و hayeah .
لماذا تحتاج where على الإطلاق؟
إنها مجرد عملية insert .

reggi يقرأ مثال MongoDB الذي قدمته "أولاً حاول التحديث إلى أين ... ثم قم بإدخال إذا لم يكن هناك مستند يطابق الاستعلام" بينما يقرأ SQL UPSERT "INSERT INTO ... UPDATING في حالة وجود صف بهذا المفتاح الأساسي بالفعل" .
لذا ، أعتقد أنك تتحدث عن "مفاجئ" مختلف تمامًا عن تطبيقه في قواعد بيانات SQL.

أود أن أقترح واجهة برمجة التطبيقات هذه:

knex.createTable('test')
   .bigserial('id')
   .varchar('unique').notNull().unique()
   .varchar('whatever')

knex.table('test').insert(object, { upsert: ['unique'] })

تقوم الدالة .insert() بتحليل المعلمة الثانية.
إذا كانت سلسلة ، فهي المعلمة returning القديمة.
إذا كان كائنًا ، فهو عبارة عن معلمة options بها options.returning و options.upsert ، حيث options.upsert عبارة عن قائمة بالمفاتيح الفريدة (يمكن أن تكون> 1 في حالة القيد الرئيسي المركب الفريد).
ثم يتم إنشاء استعلام SQL والذي يستبعد ببساطة المفتاح الأساسي وجميع مفاتيح options.upsert من object (عبر clone(object) && delete cloned_object.id && delete cloned_object.unique ) ثم يستخدم cloned_object الذي تم تجريده من المفاتيح الأساسية (والفريدة) لإنشاء جملة SET في الجزء الثاني من استعلام SQL: ... ON CONFLICT DO UPDATE SET [iterate cloned_object] .

أعتقد أن هذا سيكون الحل الأكثر بساطة ولا لبس فيه والمتجانس مع واجهة برمجة التطبيقات الحالية.

slavafominScionOfBytes يبدو أنه حتى واجهة برمجة التطبيقات (API) لم يتم الاتفاق عليها بعد. ستكون هذه هي الخطوة التالية وبعد ذلك قد يفعل ذلك الشخص الذي يحب تنفيذها. لذلك لا يوجد أخبار.

ملاحظة. لقد بدأت في حذف أي طلبات إضافية للأخبار إذا لم يكن هناك أي شيء يمنع ملء هذا الموضوع من البريد العشوائي لطلب الأخبار والرسائل الأخرى الأقل صلة.

@ amir-s أوافق ، لكن موضوع هذه المسألة هو قدرة upert.

IMO ، المشكلة الحقيقية ليست API ، ولكن الطريقة غير المألوفة للقيام بعمليات رفع في كل قاعدة بيانات.

تدعم MySQL (على التحديث الرئيسي المكرر) و PostgreSQL 9.5+ (عند تحديث CONFLICT) دعم upert افتراضيًا.

يمكن لـ MSSQL و Oracle دعمها بجملة دمج ، ولكن يجب أن تعرف knex أسماء أعمدة التعارض لتتمكن من إنشاء الاستعلام.

-- in this case the conflict column is 'a'
merge into target
using (values (?)) as t(a)
on (t.a = target.a)
when matched then
  update set b = ?
when not matched then
  insert (a, b) values (?, ?);

لكن سكليتي لم تفعل ذلك. نحتاج استعلامين لمحاكاة الصعود

-- 'a' is the conflict column
insert or ignore into target (a, b) values (?, ?);
update target set b = ?2 where changes() = 0 and a = ?1;

أو باستخدام INSERT OR REPLACE ، ويعرف أيضًا باسم REPLACE

-- replace will delete the matched row then add a new one with the given data
replace into target (a, b) values (?, ?);

لسوء الحظ ، إذا كان الجدول الهدف يحتوي على أعمدة أكثر من أ و ب ، فسيتم استبدال قيمهما بالقيم الافتراضية

insert or replace into target (a, b, c) values (?, ?, (select c from target where a = ?1))

حل آخر باستخدام CTE ، انظر إلى إجابة التدفق التراكمي

لقد جئت إلى هذه المشكلة عدة مرات بحثًا عن وظيفة Postgres upert القائمة على knex. إذا احتاج أي شخص آخر إلى ذلك ، فإليك كيفية القيام بذلك. لقد اختبرت هذا مقابل كل من المفاتيح الفريدة الفردية والمركبة.

وانشاء

قم بإنشاء قيد مفتاح فريد على الجدول باستخدام ما يلي. كنت بحاجة لقيد مفتاح مركب:

table.unique(['a', 'b'])

الوظيفة

(تحرير: تم التحديث لاستخدام ارتباطات المعلمات الأولية)

const upsert = (params)=> {
  const {table, object, constraint} = params;
  const insert = knex(table).insert(object);
  const update = knex.queryBuilder().update(object);
  return knex.raw(`? ON CONFLICT ${constraint} DO ? returning *`, [insert, update]).get('rows').get(0);
};

إستعمال

const objToUpsert = {a:1, b:2, c:3}

upsert({
    table: 'test',
    object: objToUpsert,
    constraint: '(a, b)',
})

إذا لم يكن القيد الخاص بك مركبًا ، فمن الطبيعي أن يكون هذا السطر هو constraint: '(a)' .

سيؤدي هذا إلى إرجاع الكائن المحدث أو الكائن المدرج.

ملاحظة حول الفهارس المعدلة المركبة

إذا كان لديك فهرس مركب (a,b) و b غير صالح ، فإن قيم (1, NULL) و (1, NULL) تعتبر فريدة بشكل متبادل من قبل Postgres (لم أحصل عليها إما). إذا كانت هذه هي حالة الاستخدام الخاصة بك ، فستحتاج إلى عمل فهرس فريد جزئي ثم اختبار القيمة الفارغة قبل رفع المستوى لتحديد القيد الذي يجب استخدامه. إليك كيفية عمل الفهرس الفريد الجزئي: CREATE UNIQUE INDEX unique_index_name ON table (a) WHERE b IS NULL . إذا حدد اختبارك أن b فارغ ، فستحتاج إلى استخدام هذا القيد في النتيجة: constraint: '(a) WHERE b IS NULL' . إذا كان a قابلًا للإلغاء أيضًا ، فأعتقد أنك ستحتاج إلى 3 مؤشرات فريدة و 4 if/else فروع (على الرغم من أن هذه ليست حالة الاستخدام الخاصة بي ، لذلك لست متأكدًا).

ها هي جافا سكريبت المترجمة .

أملي أن يجد هذا نفعا. elhigu هل من تعليق على استخدام knex().update(object) ؟ (تحرير: nevermind - شاهد التحذير - باستخدام knex.queryBuilder() الآن)

timhuff يبدو جيدًا ، شيء واحد لتغييره هو تمرير كل استعلام إلى خام ، باستخدام ربط القيمة. بخلاف ذلك ، يتم استخدام query.toString() لعرض كل جزء من الاستعلام ويفتح ثقبًا محتملاً لإدخال التبعية (لا يعتبر queryBuilder.toString () آمنًا مثل تمرير المعلمات إلى برنامج التشغيل مثل الروابط) ..

elhigu انتظر ... query.toString() لا يستخدم الروابط؟ هل يمكن أن تعطيني مثالاً تقريبيًا على التعديل الذي توصي به؟ أنا ... قد يكون لدي الكثير من التعليمات البرمجية لتحديثها.

تم العثور على جزء من الوثائق يسمى الروابط الأولية . التحديث الآن لقد قمت بتحديث المثال. اعتقدت أن query.toString آمن. سيكون من الجيد أن يكون لديك قسم من الوثائق يسمى شيئًا مثل "كيفية عمل استعلامات غير آمنة". لا يوجد سوى عدد قليل من no-nos وبهذه الطريقة يمكن للأشخاص استخدام المكتبة وهم يعرفون "طالما أنني لا أفعل هذه الأشياء ، فأنا بأمان".

لقد قمت بإنشاء upert التالي: https://gist.github.com/adnanoner/b6c53482243b9d5d5da4e29e109af9bd
انها تتعامل مع المنجزات الفردية والدفعية. لقد قمت بتعديلها قليلاً من plurch . التحسينات موضع تقدير دائمًا :)

لما كان يستحق استخدام هذا التنسيق:

تحرير: تم التحديث ليكون آمنًا لأي شخص يبحث عن هذا. شكرا elhigu

const query = knex( 'account' ).insert( accounts );
const safeQuery = knex.raw( '? ON CONFLICT DO NOTHING', [ query ]);

NicolajKN لا يجب عليك استخدام toString () ، فقد يتسبب ذلك في العديد من المشاكل ولن يمرر القيم من خلال الارتباطات إلى DB (ثقب أمان محتمل لحقن SQL).

نفس الشيء الذي تم القيام به بشكل صحيح سيكون كالتالي:

const query = knex('account').insert(accounts);
const safeQuery = knex.raw('? ON CONFLICT DO NOTHING', [query]);

مناقشة حذف لقضية ليست ذات صلة.

elhigu Hold on ألا يتم تنفيذ استعلام الإدراج هذا فور إنشائه؟ ألا يخلق ذلك حالة سباق؟

cloutiertyler لم تكن تتحدث معي ولكن ربما يمكنني توفير elhigu بعض الوقت هنا. لن يتم تنفيذ أي من هذه الاستفسارات. العبارة knex('account').insert(accounts) لا تنفذ استعلامًا. لا يتم تنفيذه حتى يتم استدعاء البيانات فعليًا (على سبيل المثال ، عبر .then ). يرسل ذلك إلى knex.raw('? ON CONFLICT DO NOTHING', [query]) والذي سيستدعي query.toString() ، والذي يحول الاستعلام فقط إلى عبارة SQL التي سيتم تنفيذها.

timhuff شكرًا تيم ، لقد افترضت أنه يجب أن يكون شيئًا من هذا القبيل ، لكن هذا ليس سلوكًا طبيعيًا لوعد. عادة ما يتم تنفيذ الوعود عند الخلق. السبب الذي أطلبه هو أنني كنت أتلقى أخطاء تقول "تم إنهاء الاتصال" بين الحين والآخر عندما كنت أحاول تشغيل هذا الأمر المفاجئ. بمجرد أن قمت بالتبديل إلى إزالة الإدخال وإنشاء استعلام خام بالكامل ذهبوا بعيدًا. يبدو أن هذا سيكون متسقًا مع حالة السباق.

knex QueryBuilder s ليست Promise s ، بالرغم من ذلك. عندما تبدأ في كتابة استعلام knex ، فإنك تبقى في "knexland". كل ما تفعله هو تكوين مواصفات JSON للاستعلام الذي تريد إنشاؤه بشكل أو بآخر. إذا قمت بتشغيل .toString ، فإنه ينشئه ويخرجه. لا يصبح الوعد ( bluebird ) حتى تقوم بتشغيل أحد هذه الوعد عليه. قد تكون مهتمًا باستخدام .return إذا كنت تريد تنفيذ العبارة على الفور.

آه ، أرى ، حسنًا ، هذا يوضح حيرتي. شكرا للتوضيح والمؤشرات! يجب أن توجد مشكلتي في مكان آخر بعد ذلك.

جانبا ، حقيقة أنه لا يعمل على الفور غالبا ما تكون مفيدة. في بعض الأحيان تريد تمرير الشيء ، وتكوينه ، قبل التنفيذ. هناك أيضًا مواقف يمكنك فيها القيام بأشياء مثل ...

const medicalBuildings = knex.select('building_id').from('buildings').where({type: 'medical'})
const medicalWorkers = knex.select().from('workers').whereIn('building', medicalBuildings)

(مثال مفتعل بشكل فائق ولكن دعنا نجري معه)

لا أريد في الواقع تشغيل العبارة الأولى - إنها مجرد جزء من العبارة الثانية.

ناهيك عن أنه إذا تم تنفيذ جميع منشئي الاستعلامات عند الإنشاء ، فسيتم تشغيل استعلامات أنماط الباني قبل إتمام البناء. لن يعمل على الإطلاق بدون وجود طريقة فاصلة (التي تنفذ الاستعلام).

elhigu أعني ... أعتقد أنه يمكنك دائمًا تشغيله في العلامة التالية ، أليس كذلك؟ لا أقترح أن تكون فكرة جيدة بأي حال من الأحوال ، ولكن كم عدد الاستعلامات التي تم إنشاؤها وتنفيذها فعليًا على علامات التجزئة المختلفة؟

timhuff لم أفكر في ذلك. نعم أعتقد أن ذلك سيكون ممكنًا أيضًا. أجد حالة شائعة جدًا حيث يبدأ المرء في إنشاء استعلام ، ثم أحضر بعض البيانات غير المتزامنة واستمر في بناء المزيد. على الرغم من أنني لا أفعل ذلك كثيرًا.

lukewlms أن "تنفيذ ()" طريقة شبيهة تسمى ". ثم ()" يمكنك الاتصال بها دائمًا عندما ترغب في تنفيذ الاستعلام والحصول على الوعد. إنها مجرد طريقة عمل "قابلة للإصدار" ويتم شرحها في المواصفات الوعدية. إنه مفهوم مهم وشائع الاستخدام في جافا سكريبت عند التعامل مع الوعود وعدم التزامن / الانتظار (وهي اختصارات مجيدة إلى حد كبير لـ Promise.resolve و. ثم). أيضًا إذا كنت تنفذ استعلامات دون معالجة النتائج ، فأنت تبحث عن مشكلات مثل تعطل التطبيق.

في الواقع ، من الأفضل متابعة هذه العلاقات العامة حول تنفيذ ميزة upert https://github.com/tgriesser/knex/pull/2197 ، فقد صممت واجهة برمجة التطبيقات بالفعل كيفية عملها. في هذا الموضوع ليس في الواقع أي معلومات مفيدة لم يتم ذكرها بالفعل في تعليقات ذلك العلاقات العامة. إذا لزم الأمر (إغلاق العلاقات العامة ولم يكتمل أبدًا) يتيح فتح إصدار جديد لهذه المشكلة مع وصف إضافي لواجهة برمجة التطبيقات.

elhigu شكرا على التنبيه! لم أكن على علم بهذا الموضوع. من الجيد أن نسمع أننا نحرز تقدمًا بشأن وصول مفاجئ إلى واجهة برمجة التطبيقات. يبدو أنه قبل 6 أشهر فشل في اختبار واحد من 802 اختبارًا ولذلك لم ينجح أبدًا في اجتياز اختبار travis-ci. هل هذه حالة الاختبار 1 الفاشلة هي الشيء الوحيد الذي يمنع هذا من أن يصبح جزءًا من واجهة برمجة تطبيقات knex؟

timhuff كان هناك تنفيذ أولي فقط تم القيام به ، ويجب إعادة كتابته بالكامل. الجزء الأكثر أهمية في هذا العلاقات العامة هو تصميم API المشترك ، والذي يمكن أن تدعمه معظم اللهجات. لذلك تأتي الميزة عندما يقرر شخص ما تنفيذ واجهة برمجة التطبيقات تلك. إذا لم يفعل ذلك أي شخص آخر وفي يوم من الأيام كان لدي بعض الوقت الإضافي أو كنت في حاجة ماسة إليه ، فسأفعل ذلك بنفسي. هذه واحدة من أهم الميزات التي أرغب في الحصول عليها من Knex (بالإضافة إلى عمليات الانضمام في التحديثات).

elhigu شكرًا على ملء بياناتي. سأضطر إلى قراءة التقدم هنا عندما أحصل على مزيد من الوقت.

لست متأكدًا مما إذا كان هذا يساعد أي شخص أو إذا كنت مجرد مستجد ، ولكن بالنسبة للحل من timhuff ، كان عليّ أن ألّف القيد الخاص بي في علامات الاقتباس لأنني كنت أتلقى خطأ في بناء جملة الاستعلام.

const contraint = '("a", "b")'

لقد جئت إلى هذه المشكلة عدة مرات بحثًا عن وظيفة Postgres upert القائمة على knex. إذا احتاج أي شخص آخر إلى ذلك ، فإليك كيفية القيام بذلك. لقد اختبرت هذا مقابل كل من المفاتيح الفريدة الفردية والمركبة.

وانشاء

قم بإنشاء قيد مفتاح فريد على الجدول باستخدام ما يلي. كنت بحاجة لقيد مفتاح مركب:

table.unique(['a', 'b'])

الوظيفة

(تحرير: تم التحديث لاستخدام ارتباطات المعلمات الأولية)

const upsert = (params)=> {
  const {table, object, constraint} = params;
  const insert = knex(table).insert(object);
  const update = knex.queryBuilder().update(object);
  return knex.raw(`? ON CONFLICT ${constraint} DO ? returning *`, [insert, update]).get('rows').get(0);
};

إستعمال

const objToUpsert = {a:1, b:2, c:3}

upsert({
  table: 'test',
  object: objToUpsert,
  constraint: '(a, b)',
})

إذا لم يكن القيد الخاص بك مركبًا ، فمن الطبيعي أن يكون هذا السطر هو constraint: '(a)' .

سيؤدي هذا إلى إرجاع الكائن المحدث أو الكائن المدرج.

ملاحظة حول الفهارس المعدلة المركبة

إذا كان لديك فهرس مركب (a,b) و b غير صالح ، فإن قيم (1, NULL) و (1, NULL) تعتبر فريدة بشكل متبادل من قبل Postgres (لم أحصل عليها إما). إذا كانت هذه هي حالة الاستخدام الخاصة بك ، فستحتاج إلى عمل فهرس فريد جزئي ثم اختبار القيمة الفارغة قبل رفع المستوى لتحديد القيد الذي يجب استخدامه. إليك كيفية عمل الفهرس الفريد الجزئي: CREATE UNIQUE INDEX unique_index_name ON table (a) WHERE b IS NULL . إذا حدد اختبارك أن b فارغ ، فستحتاج إلى استخدام هذا القيد في النتيجة: constraint: '(a) WHERE b IS NULL' . إذا كان a قابلًا للإلغاء أيضًا ، فأعتقد أنك ستحتاج إلى 3 مؤشرات فريدة و 4 if/else فروع (على الرغم من أن هذه ليست حالة الاستخدام الخاصة بي ، لذلك لست متأكدًا).

ها هي جافا سكريبت المترجمة .

أملي أن يجد هذا نفعا. elhigu ~ أي تعليق على استخدام knex().update(object) ؟ ~ (تعديل: لا يهم - شاهد التحذير - باستخدام knex.queryBuilder() الآن)

إزالة بعض المناقشات غير ذات الصلة (حول كيفية عمل الوعود / النتائج).

هل تمت إضافة هذا؟

لا ، هناك طلب خاص بالميزات والمواصفات في https://github.com/knex/knex/issues/3186

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات