Как использовать $ фильтр во вложенном массиве в пн go дБ? - PullRequest
0 голосов
/ 18 марта 2020

У меня есть следующие документы в модели сельского хозяйства

{
"_id" : ObjectId("5e5c9c0a0cfcdb1538406000"),
"agricultureProductSalesType" : [ 
    "cash_crops", 
    "vegetable", 
    "fruit"
],
"flag" : false,
"agricultureDetail" : [ 
    {
        "production" : {
            "plantCount" : 0,
            "kg" : 0,
            "muri" : 0,
            "pathi" : 0
        },
        "sale" : {
            "plantCount" : 0,
            "kg" : 0,
            "muri" : 0,
            "pathi" : 0
        },
        "_id" : ObjectId("5e5c9c0a0cfcdb1538406001"),
        "title" : "alaichi",
        "agricultureProductionSalesType" : "cash_crops"
    }, 
    {
        "production" : {
            "plantCount" : 0,
            "kg" : 40,
            "muri" : 0,
            "pathi" : 0
        },
        "sale" : {
            "plantCount" : 0,
            "kg" : 0,
            "muri" : 0,
            "pathi" : 0
        },
        "_id" : ObjectId("5e5c9c0a0cfcdb1538406002"),
        "title" : "amriso",
        "agricultureProductionSalesType" : "cash_crops"
    }
],
"agricultureParent" : [ 
    {
        "area" : {
            "ropani" : 10,
            "aana" : 0,
            "paisa" : 0
        },
        "_id" : ObjectId("5e5c9c0a0cfcdb1538406005"),
        "title" : "cash_crops",
        "income" : 50000,
        "expense" : 6000
    }
],
"house" : ObjectId("5e5c9c090cfcdb1538405fa9"),
"agricultureProductSales" : true,
"insecticides" : false,
"fertilizerUse" : true,
"seedNeed" : "local",
"__v" : 0

Я хочу получить результат из вышеуказанного документа с условием, если сельского хозяйстваDetail.title не является пустой или пустой строкой И сельское хозяйствоDetail.production.plantcount равно нулю или нулю или существует false AND сельское хозяйствоDetail.production.kg равно нулю или нулю или существует ложь И (все оставшиеся элементы внутри продукции равны нулю или нулю или существует в пламени).

Я попытался $ elemMatch, как показано ниже:

 $and: [
      { agricultureProductSales: true },
      { agricultureDetail: { $exists: true, $ne: [] } },
      {
        $or: [
          { agricultureDetail: { $elemMatch: { title: { $ne: "" } } } },
          {
            agricultureDetail: { $elemMatch: { title: { $exists: true } } }
          }
        ]
      },
      {
        $or: [
          {
            agricultureDetail: {
              $elemMatch: { production: { $exists: true } }
            }
          },
          {
            agricultureDetail: {
              $elemMatch: { production: { $ne: [] } }
            }
          }
        ]
      },
      {
        $or: [
          {
            "agricultureDetail.production": {
              $elemMatch: { plantCount: { $exists: false } }
            }
          },
          {
            "agricultureDetail.production": {
              $elemMatch: { plantCount: { $eq: 0 } }
            }
          },
          {
            "agricultureDetail.production": {
              $elemMatch: { plantCount: { $eq: null } }
            }
          }
        ]
      }
    ]

Но это возвращает пустой результат. Любая помощь? Большое спасибо.

1 Ответ

1 голос
/ 19 марта 2020

Немного разбив этот запрос:

{ agricultureProductSales: true },

Выбирает только истинные значения.

{ agricultureDetail: { $exists: true, $ne: [] } }

Постороннее. Так как вы тестируете поля вложенных документов в этом массиве, эти более поздние тесты не могли бы быть успешными, если массив был пуст или не существовал.

 {
        $or: [
          { agricultureDetail: { $elemMatch: { title: { $ne: "" } } } },
          {
            agricultureDetail: { $elemMatch: { title: { $exists: true } } }
          }
        ]
      },

Этот тест проверяет, если title или нет 't равно "" (которое включает элементы, в которых поле не существует) или если поле title существует. Одно из них всегда верно, поэтому этот $or всегда будет совпадать. Если вы хотите сопоставлять только те документы, которые содержат элемент с непустым заголовком, проверьте, не превышает ли он "" - поскольку операторы запросов чувствительны к типу, это не будет соответствовать любому title, который не не существует, не содержит строку или содержит пустую строку.

  "agricultureDetail.title": { $gt: "" }

Аналогично plantCount, если бы вы проверяли $gt: 0, это соответствовало бы только документам, содержащим plantCount это число c и больше 0. То, что вы хотите, является логической инверсией этого, поэтому:

  "agricultureDetail.production.plantCount": {$not: {$gt: 0}}

В этом случае это будет соответствовать элементам, которые не содержат поле production, или те, которые имеют пустой массив для поля production.

Тест существования для plantCount исключит обе эти возможности, поэтому

  "agricultureDetail.production.plantCount": {$exists:true, $not: {$gt: 0}}

Как написано, все они проверяют, соответствует ли какой-либо элемент в массиве любой критериев.

Если ваше намерение состоит в том, чтобы соответствовать документу, содержащему один элемент, который соответствует всем критериям, вы должны собрать их вместе в $elemMatch из agricultureDetail поля. Таким образом, окончательный запрос может выглядеть примерно так:

db.collection.find({
    agricultureProductSales: true,
    agricultureDetail:{$elemMatch:{
          title: {$gt: ""},
          "production.plantCount": {$exists:true, $not: {$gt: 0}}
    }}
})

Playground

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...