Neoclassical Programming Multitude


    7.2.2 • Public • Published

    MARC record implementation in JavaScript

    NPM Version Build Status Test Coverage

    MARC record implementation in JavaScript. A JSON schema file specifies the data format.

    This a fork of the original marc-record-js. The new implementation uses ES6 syntax and adds validation of the record structure.


    import {MarcRecord} from '@natlibfi/marc-record';
    const record = new MarcRecord();

    Create record from object

    const record = new MarcRecord(
        leader: 'foo',
        fields: [
          {tag: '001', value: 'foo'},
          {tag: '002', value: 'bar'},

    Cloning a record

    const recordB = MarcRecord.clone(recordA)

    Record validation

    When constructing or modifying the record, validation checks are run. You may need to alter these checks to work with incomplete intermediate records.

    Global validation options:

    // Default settings
        fields: true,          // Do not allow record without fields
        subfields: true,       // Do not allow empty subfields
        subfieldsValues: true, // Do not allow subfields without value

    You can reset global validation options to default with empty object:

    // Reset to default

    Record specific validation options can be given when constructing:

    const record = new MarcRecord(
        leader: 'foo',
        fields: []
      {fields: false} // Allow empty fields

    Validation examples:

    The following examples demonstrate the invalid records, when default validation options are used. To fix the errors, either fix the record, or modify global/record-specific validation options.

    // Error: fields[] is empty. Validation option: fields
    new MarcRecord(
        leader: 'foo',
        fields: []
    // Error: subfields[] is empty. Validation option: subfields
    new MarcRecord(
        leader: 'foo',
        fields: [
          {tag: "021", subfields: []}
    // Error: subfield has no value. Validation option: subfieldValues
    new MarcRecord(
        leader: 'foo',
        fields: [
          {tag: "021", subfields: [{code: "a", value: ""}]}

    Record equality check

    MarcRecord.isEqual(recordA, recordB);

    Querying for fields

    get() returns fields which tags match the specified pattern:

    record.get("776")         // Return fields with tag 776
    record.get(/020|021/u)    // Return fields matching the regexp

    getControlfields() returns so called control fields, that is, fields with simple value. These are generally fields 001 - 008.

    record.getControlfields();  // Return all control fields

    getDatafields() returns fields with subfields.

    record.getDatafields();     // Return all data fields

    getFields() fetches fields from record.

    To get all 245 fields:


    To get all 001 fields which values is foo:

    record.getFields('001', 'foo');

    To get all 245 fields, which have specific subfields. All subfields given as argument should be present in the fetched fields:

    // Fetch all 245 fields containing subfields a and b with specified values
    record.getFields('245', [{code: 'a', value: 'foo'}, {code: 'b', value: 'bar'}]);

    containsFieldWithValue() uses the same arguments than getFields(). It is a shorthand to check, if getFields() returns more than an empty list.

    record.containsFieldWithValues('001', 'foo'); // getFields('001', 'foo').length > 0
    record.containsFieldWithValues('245', [{code: 'a', value: 'foo'}]);

    Custom queries: You can access record fields to implement your custom queries.

    record.fields;    // Access to record fields

    Adding fields

    insertField / insertFields: Insertion handles the proper field ordering automatically.

    // Insert single field
    record.insertField({tag: "001", value: "foo"});
    // Chained inserts
      .insertField({tag: "001", value: "A"})
      .insertField({tag: "003", value: "C"})
      .insertField({tag: "002", value: "B"});
    // Insert from array:
      {tag: "001", value: "A"},
      {tag: "003", value: "C"},
      {tag: "002", value: "B"}

    appendField / appendFields: Appending fields to the end of record. In general, you close always use insert instead of append.

    // Append single field:
    record.appendField({tag: "001", value: "foo"});
    // Chained appending
      .appendField({tag: "001", value: "A"})
      .appendField({tag: "003", value: "C"})
      .appendField({tag: "002", value: "B"});
    // Append from array
      {tag: "001", value: "A"},
      {tag: "003", value: "C"},
      {tag: "002", value: "B"}

    Removing fields

    Removing a field ONLY removes fields that are in the record. It DOES NOT compare the field content to find field.

    So, always use queries to remove fields:

    // Remove all 020 and 021 fields
    const fields = record.get(/020|021/u);	// Returns an array
    record.removeFields(fields); // Removes fields in array of matching fields

    Failing examples:

    // Example record
    const record = new MarcRecord(
      leader: "foo",
      fields: [
        {tag: "001", value: "bar"}
    // FAIL: Even if fields have same values, they are different fields
    record.removeField({tag: "001", value: "bar"})
    // FAIL: removeField accepts fields, not strings
    record.removeField("001")     // FAIL: removeField does not perform query
    record.removeField(/^001$/u)  // FAIL: removeField does not perform query
    // FAIL: insertField (may) insert copy of a parameter field
    const field = {tag: "300", subfields: [{code: "a", value: "b"}]}
    // "Direct query"
    const field = record.fields[2];
    record.removeField({...field})  // Obvious FAIL
    record.removeField(field) // OK

    Popping fields

    Popping fields with queries. Query matches field tag. Matched fields are returned, and removed from record. Once you have modified the fields according to your needs, you can push them back with insert.

    // Record tags: [001, 001, 002, 003, 003, 004, 005, 006]
    // 1) Pop fields with query:
    fields = record.pop(/(001|004)/u);
    // Result:
    // - Field tags: [001, 001, 004]
    // - Record tags: [002, 003, 003, 005, 006]
    // 2) Do something with fields
    // 3) Push back modified fields:
    // Result: Record tags: [001, 001, 002, 003, 003, 004, 005, 006]

    Sorting fields



    Sorting, inserting and removing can be chained together:

      .removeFields(record.get(/005/u))       // Remove all 005 fields
      .insertField({tag: "005", value: "A"})  // Insert new 005 field
      .sortFields();                          // Sort fields
    // Note: In this case, there is no need for sort, as insert puts the field to
    // correct place. It is there just as an example.

    See also

    To serialize and unserialize MARC records, see marc-record-serializers

    License and copyright

    Copyright (c) 2014-2017 Pasi Tuominen

    Copyright (c) 2018 University Of Helsinki (The National Library Of Finland)

    This project's source code is licensed under the terms of MIT License or any later version.


    npm i @natlibfi/marc-record

    DownloadsWeekly Downloads






    Unpacked Size

    331 kB

    Total Files


    Last publish


    • natlibfi-jonollil
    • drone-melinda