All skills

Waterline ORM query language, model definitions, associations, and data access patterns for Sails.js. Use this skill when writing, reviewing, or debugging Waterline queries, model attributes, associations, lifecycle callbacks, validations, or any database interaction in a Sails.js application.

Use this Skill: https://skilld.dev/gh/sailscastshq/boring-stack/waterline

This session only. Nothing lands on disk.

rulescollections-and-advanced.md

≈1.7k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Collections and Advanced Features

addToCollection()

Add child records to a many-to-many or one-to-many association. Does NOT create new records -- only establishes relationships.

// Add courses to a user's collection
await User.addToCollection(userId, 'courses', [courseId])

// Add from the other side
await Course.addToCollection(courseId, 'purchasers', [userId])

// Add multiple at once
await User.addToCollection(userId, 'courses', [course1, course2, course3])

// Using .members() syntax
await User.addToCollection(userId, 'pets').members([petId1, petId2])

Behavior:

  • Duplicate associations are silently skipped (no error for re-adding)
  • Empty child IDs array is a no-op
  • Non-existent parent/child IDs are silently handled
  • Two-way associations (via) are automatically kept in sync

removeFromCollection()

Remove associations (NOT the records themselves):

// Remove courses from a user
await User.removeFromCollection(userId, 'courses', [courseId])
await Course.removeFromCollection(courseId, 'purchasers', [userId])

// Using .members() syntax
await Invoice.removeFromCollection(invoiceId, 'items').members(
  idsOfItemsRemoved
)

// Remove from multiple parents at once
await User.removeFromCollection([userId1, userId2], 'courses', [courseId])

Behavior:

  • Child records are NOT destroyed -- only the association is removed
  • Non-existent IDs are silently ignored
  • Already-absent associations are silently skipped

replaceCollection()

Replace ALL child records in a collection. Detaches existing members and attaches the new set:

// Replace user's courses with a new set
await User.replaceCollection(userId, 'courses').members([course1, course2])

// Empty array detaches ALL members
await User.replaceCollection(userId, 'courses').members([])

archive() and archiveOne()

Soft-delete by copying records to the built-in Archive model, then destroying the originals:

// Archive matching records
await Pet.archive({
  lastActiveAt: { '<': Date.now() - 365 * 24 * 60 * 60 * 1000 }
})

// Archive a single record
var archived = await User.archiveOne({ firstName: 'Finn' })
if (archived) {
  sails.log('Archived user:', archived.id)
}

// With .fetch() to get archived records (on archive, not archiveOne)
var archivedRecords = await User.archive({ inactive: true }).fetch()

Retrieve archived data:

var record = await Archive.findOne({
  fromModel: 'user',
  originalRecordId: 1
})
// record.originalRecord contains the original data

Caveats:

  • No built-in unarchive functionality
  • If you need un-delete, consider using an isDeleted boolean flag instead
  • archiveOne() throws if criteria matches more than one record

native() (Deprecated)

Direct access to the underlying database driver. MongoDB only. Use getDatastore().manager instead:

// Modern approach
var db = sails.getDatastore().manager

For SQL databases, use raw queries via the adapter.

.meta()

Pass metadata through to the adapter. A pass-through dictionary that flows from userland to the database driver:

// Force fetch on create
await User.create({ name: 'Finn' }).meta({ fetch: true }) // Same as .fetch()

// Force decryption
await User.find().meta({ decrypt: true }) // Same as .decrypt()

// Custom batch size for stream
await User.stream({})
  .meta({ batchSize: 100 })
  .eachRecord(async (user) => {})

// Skip deep-cloning of criteria (performance optimization)
await User.find(criteria).meta({ mutateArgs: true })

Key recognized meta keys:

  • fetch: true -- Make create/update/destroy return affected records
  • decrypt: true -- Decrypt encrypted attributes
  • batchSize: N -- Custom batch size for .stream()
  • mutateArgs: true -- Skip deep-cloning criteria (performance)

.decrypt()

Decrypt attributes that have encrypt: true on the model:

var user = await User.findOne({ id: 1 }).decrypt()
// user.ssn is now the plaintext value

Without .decrypt(), encrypted attributes remain as ciphertext.

.fetch()

Make create/update/destroy return the affected records. Without .fetch(), these methods return nothing for performance:

// create + fetch
var newUser = await User.create({ name: 'Finn' }).fetch()

// update + fetch
var updated = await User.update({ active: false }).set({ active: true }).fetch()

// destroy + fetch
var deleted = await User.destroy({ expired: true }).fetch()

Note: updateOne(), destroyOne(), and archiveOne() always return the record -- they do NOT support .fetch().

Background Operations with Callbacks

Run a query without await -- useful for fire-and-forget background tasks. Use the callback form instead of awaiting:

// Background user update (no await -- runs behind the scenes)
User.updateOne({ id: loggedInUser.id })
  .set({ lastSeenAt: Date.now() })
  .then(() => {})
  .catch((err) => {
    sails.log.error('Background task failed:', err)
  })

Chainable Methods Quick Reference

Method Available On
.where() find, count, sum, avg
.sort() find, stream
.limit() find, stream
.skip() find, stream
.select() find, findOne
.omit() find, findOne
.populate() find, findOne, stream
.fetch() create, createEach, update, destroy, archive
.set() update, updateOne
.members() addToCollection, removeFromCollection, replaceCollection
.decrypt() find, findOne, create, createEach, update, stream
.meta() All methods
.intercept() All async methods
.tolerate() All async methods
.usingConnection() All async methods (in transactions)
.eachRecord() stream
.eachBatch() stream
.paginate() find

Source: SKILL.md on GitHub

1 warning17d4 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill provides comprehensive documentation and best practice rules for writing Waterline ORM queries and model definitions in Sails.js applications. It contains only Markdown files and does not include any executable scripts or malicious instructions.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer7mo

    10/13 files flagged

Signed by skilld at 383ecf8. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 days ago.

Activeupdated 8 months ago
Other metadata
metadata
{
  "author": "sailscastshq",
  "version": "1.0.0",
  "tags": "waterline, sails, orm, database, query, models"
}

README badge

README badge for sailscastshq/boring-stack/waterline