MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Truy vấn về Ngày khớp trong Mảng

Bạn đang thiếu $elemMatch toán tử trên truy vấn cơ bản và $filter bạn đã cố gắng với khung tổng hợp thực sự có cú pháp không chính xác.

Vì vậy, trả về tài liệu khớp với ngày nằm trong phạm vi đó trong mảng là:

// Simulating the date values
var start = new Date("2018-06-01"); // otherwise new Date(req.params.start)
var end = new Date("2018-07-01");   // otherwise new Date(req.params.end)

myColl.find({ 
  "_id": req.params.id,
  "someArray": {
    "$elemMatch": {  "$gte": start, "$lt": end  }
  }
}).then( doc => {
  // do something with matched document
}).catch(e => { console.err(e); res.send(e); })

Lọc các phần tử mảng thực tế sẽ được trả về là:

// Simulating the date values
var start = new Date("2018-06-01");
var end = new Date("2018-07-01");

myColl.aggregate([
  { "$match": { 
    "_id": mongoose.Types.ObjectId(req.params.id),
    "someArray": {
      "$elemMatch": { "$gte": start, "$lt": end }
    }
  }},
  { "$project": {
    "name": 1,
    "someArray": {
      "$filter": {
        "input": "$someArray",
        "cond": {
          "$and": [
            { "$gte": [ "$$this.Timestamp", start ] }
            { "$lt": [ "$$this.Timestamp", end ] }
          ]
        }
      }
    }
  }}
]).then( docs => {
  /* remember aggregate returns an array always, so if you expect only one
   * then it's index 0
   *
   * But now the only items in 'someArray` are the matching ones, so you don't need 
   * the code you were writing to just pull out the matching ones
   */
   console.log(docs[0].someArray);
  
}).catch(e => { console.err(e); res.send(e); })

Những điều cần lưu ý là trong aggregate() bạn cần thực sự "truyền" ObjectId giá trị, bởi vì "autocasting" trong Mongoose không hoạt động ở đây. Thông thường mongoose đọc từ lược đồ để xác định cách truyền dữ liệu, nhưng vì các đường ống tổng hợp "thay đổi mọi thứ" nên điều này không xảy ra.

$elemMatch ở đó vì như tài liệu cho biết :

Tóm lại $gte $lt là một điều kiện AND và được tính là "hai", do đó, dạng "ký hiệu dấu chấm" đơn giản không áp dụng. Nó cũng là $lt chứ không phải $lte , vì "ít hơn" "ngày hôm sau" có ý nghĩa hơn là tìm kiếm sự bình đẳng cho đến "phần nghìn giây cuối cùng".

$filter tất nhiên là thực hiện chính xác những gì tên nó gợi ý và "lọc" nội dung mảng thực tế để chỉ các mục phù hợp bị bỏ lại.

Trình diễn

Danh sách trình diễn đầy đủ tạo ra hai tài liệu, một tài liệu chỉ có hai mục mảng thực sự khớp với phạm vi ngày. Truy vấn đầu tiên hiển thị tài liệu chính xác được khớp với phạm vi. Thứ hai hiển thị "lọc" của mảng:

const { Schema, Types: { ObjectId } } = mongoose = require('mongoose');

const uri = 'mongodb://localhost/test';

mongoose.Promise = global.Promise;
mongoose.set('debug',true);

const subSchema = new Schema({
  timestamp: Date,
  other: String
});

const testSchema = new Schema({
  name: String,
  someArray: [subSchema]
});

const Test = mongoose.model('Test', testSchema, 'filtertest');

const log = data => console.log(JSON.stringify(data, undefined, 2));

const startDate = new Date("2018-06-01");
const endDate = new Date("2018-07-01");

(function() {

  mongoose.connect(uri)
    .then(conn =>
      Promise.all(Object.entries(conn.models).map(([k,m]) => m.remove()))
    )
    .then(() =>
      Test.insertMany([
        {
          _id: "5b1522f5cdac0b6da18f7618",
          name: 'A',
          someArray: [
            { timestamp: new Date("2018-06-01"), other: "C" },
            { timestamp: new Date("2018-07-04"), other: "D" },
            { timestamp: new Date("2018-06-10"), other: "E" }
          ]
        },
        {
          _id: "5b1522f5cdac0b6da18f761c",
          name: 'B',
          someArray: [
            { timestamp: new Date("2018-07-04"), other: "D" },
          ]
        }
      ])
    )
    .then(() =>
      Test.find({
        "someArray": {
          "$elemMatch": {
            "timestamp": { "$gte": startDate, "$lt": endDate }
          }
        }
      }).then(docs => log({ docs }))
    )
    .then(() =>
      Test.aggregate([
        { "$match": {
          "_id": ObjectId("5b1522f5cdac0b6da18f7618"),
          "someArray": {
            "$elemMatch": {
              "timestamp": { "$gte": startDate, "$lt": endDate }
            }
          }
        }},
        { "$addFields": {
          "someArray": {
            "$filter": {
              "input": "$someArray",
              "cond": {
                "$and": [
                  { "$gte": [ "$$this.timestamp", startDate ] },
                  { "$lt": [ "$$this.timestamp", endDate ] }
                ]
              }
            }
          }
        }}
      ]).then( filtered => log({ filtered }))
    )
    .catch(e => console.error(e))
    .then(() => mongoose.disconnect());

})()

Hoặc hiện đại hơn một chút với async/await cú pháp:

const { Schema, Types: { ObjectId } } = mongoose = require('mongoose');

const uri = 'mongodb://localhost/test';

mongoose.Promise = global.Promise;
mongoose.set('debug',true);

const subSchema = new Schema({
  timestamp: Date,
  other: String
});

const testSchema = new Schema({
  name: String,
  someArray: [subSchema]
});

const Test = mongoose.model('Test', testSchema, 'filtertest');

const log = data => console.log(JSON.stringify(data, undefined, 2));

(async function() {

  try {

    const startDate = new Date("2018-06-01");
    const endDate = new Date("2018-07-01");

    const conn = await mongoose.connect(uri);

    // Clean collections
    await Promise.all(Object.entries(conn.models).map(([k,m]) => m.remove()));

    // Create test items

    await Test.insertMany([
      {
        _id: "5b1522f5cdac0b6da18f7618",
        name: 'A',
        someArray: [
          { timestamp: new Date("2018-06-01"), other: "C" },
          { timestamp: new Date("2018-07-04"), other: "D" },
          { timestamp: new Date("2018-06-10"), other: "E" }
        ]
      },
      {
        _id: "5b1522f5cdac0b6da18f761c",
        name: 'B',
        someArray: [
          { timestamp: new Date("2018-07-04"), other: "D" },
        ]
      }
    ]);



    // Select matching 'documents'
    let docs = await Test.find({
      "someArray": {
        "$elemMatch": {
          "timestamp": { "$gte": startDate, "$lt": endDate }
        }
      }
    });
    log({ docs });

    let filtered = await Test.aggregate([
      { "$match": {
        "_id": ObjectId("5b1522f5cdac0b6da18f7618"),
        "someArray": {
          "$elemMatch": {
            "timestamp": { "$gte": startDate, "$lt": endDate }
          }
        }
      }},
      { "$addFields": {
        "someArray": {
          "$filter": {
            "input": "$someArray",
            "cond": {
              "$and": [
                { "$gte": [ "$$this.timestamp", startDate ] },
                { "$lt": [ "$$this.timestamp", endDate ] }
              ]
            }
          }
        }
      }}
    ]);
    log({ filtered });

    mongoose.disconnect();

  } catch(e) {
    console.error(e)
  } finally {
    process.exit()
  }

})()

Cả hai đều giống nhau và cho cùng một đầu ra:

Mongoose: filtertest.remove({}, {})
Mongoose: filtertest.insertMany([ { _id: 5b1522f5cdac0b6da18f7618, name: 'A', someArray: [ { _id: 5b1526952794447083ababf6, timestamp: 2018-06-01T00:00:00.000Z, other: 'C' }, { _id: 5b1526952794447083ababf5, timestamp: 2018-07-04T00:00:00.000Z, other: 'D' }, { _id: 5b1526952794447083ababf4, timestamp: 2018-06-10T00:00:00.000Z, other: 'E' } ], __v: 0 }, { _id: 5b1522f5cdac0b6da18f761c, name: 'B', someArray: [ { _id: 5b1526952794447083ababf8, timestamp: 2018-07-04T00:00:00.000Z, other: 'D' } ], __v: 0 } ], {})
Mongoose: filtertest.find({ someArray: { '$elemMatch': { timestamp: { '$gte': new Date("Fri, 01 Jun 2018 00:00:00 GMT"), '$lt': new Date("Sun, 01 Jul 2018 00:00:00 GMT") } } } }, { fields: {} })
{
  "docs": [
    {
      "_id": "5b1522f5cdac0b6da18f7618",
      "name": "A",
      "someArray": [
        {
          "_id": "5b1526952794447083ababf6",
          "timestamp": "2018-06-01T00:00:00.000Z",
          "other": "C"
        },
        {
          "_id": "5b1526952794447083ababf5",
          "timestamp": "2018-07-04T00:00:00.000Z",
          "other": "D"
        },
        {
          "_id": "5b1526952794447083ababf4",
          "timestamp": "2018-06-10T00:00:00.000Z",
          "other": "E"
        }
      ],
      "__v": 0
    }
  ]
}
Mongoose: filtertest.aggregate([ { '$match': { _id: 5b1522f5cdac0b6da18f7618, someArray: { '$elemMatch': { timestamp: { '$gte': 2018-06-01T00:00:00.000Z, '$lt': 2018-07-01T00:00:00.000Z } } } } }, { '$addFields': { someArray: { '$filter': { input: '$someArray', cond: { '$and': [ { '$gte': [ '$$this.timestamp', 2018-06-01T00:00:00.000Z ] }, { '$lt': [ '$$this.timestamp', 2018-07-01T00:00:00.000Z ] } ] } } } } } ], {})
{
  "filtered": [
    {
      "_id": "5b1522f5cdac0b6da18f7618",
      "name": "A",
      "someArray": [
        {
          "_id": "5b1526952794447083ababf6",
          "timestamp": "2018-06-01T00:00:00.000Z",
          "other": "C"
        },
        {
          "_id": "5b1526952794447083ababf4",
          "timestamp": "2018-06-10T00:00:00.000Z",
          "other": "E"
        }
      ],
      "__v": 0
    }
  ]
}



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Doctrine ODM / MongoDB không thử lại các truy vấn?

  2. Tổng quan về Xác thực lược đồ MongoDB

  3. MongoDB nhận các trạng thái thực thi cho truy vấn tổng hợp

  4. Đẩy đến hai mảng riêng biệt trong một lệnh gọi cập nhật trong mongodb

  5. Kiểm tra tích hợp với MongoDB?