MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Połącz wartości ciągu w tablicy w jednym polu w MongoDB

W wydaniach Modern MongoDB możesz. Nadal nie możesz "bezpośrednio" zastosować tablicy do $concat , jednak możesz użyć $reduce do pracy z elementami tablicy i wytworzenia tego:

db.collection.aggregate([
  { "$addFields": {
    "values": { 
      "$reduce": {
        "input": "$values",
        "initialValue": "",
        "in": {
          "$cond": {
            "if": { "$eq": [ { "$indexOfArray": [ "$values", "$$this" ] }, 0 ] },
            "then": { "$concat": [ "$$value", "$$this" ] },
            "else": { "$concat": [ "$$value", "_", "$$this" ] }
          }    
        }
      }        
    }
  }}
])

Połączenie oczywiście z $indexOfArray aby nie "połącz" z "_" podkreśl, gdy jest to „pierwszy” indeks tablicy.

Również moje dodatkowe "życzenie" zostało odebrane za pomocą $sum :

db.collection.aggregate([
  { "$addFields": {
    "total": { "$sum": "$items.value" }
  }}
])

Ten rodzaj jest nieco ogólnie podnoszony za pomocą operatorów agregacji, które pobierają tablicę elementów. Różnica polega na tym, że oznacza to „macierz” „agumentów” dostarczonych w zakodowanej reprezentacji, w przeciwieństwie do „elementu tablicy” obecnego w bieżącym dokumencie.

Jedynym sposobem, w jaki naprawdę można wykonać konkatenację elementów w tablicy znajdującej się w dokumencie, jest wykonanie jakiejś opcji JavaScript, jak w tym przykładzie w mapReduce:

db.collection.mapReduce(
    function() {
        emit( this._id, { "values": this.values.join("_") } );
    },
    function() {},
    { "out": { "inline": 1 } }
)

Oczywiście, jeśli w rzeczywistości niczego nie agregujesz, prawdopodobnie najlepszym podejściem jest po prostu wykonanie tej operacji „dołączenia” w kodzie klienta podczas przetwarzania końcowego wyników zapytania. Ale jeśli trzeba go użyć w jakimś celu w różnych dokumentach, mapReduce będzie jedynym miejscem, w którym możesz go użyć.

Mógłbym dodać, że „na przykład” bardzo bym chciał, żeby coś takiego zadziałało:

{
    "items": [
        { "product": "A", "value": 1 },
        { "product": "B", "value": 2 },
        { "product": "C", "value": 3 }
    ]
}

A w sumie:

db.collection.aggregate([
    { "$project": {
        "total": { "$add": [
            { "$map": {
                "input": "$items",
                "as": "i",
                "in": "$$i.value"
            }}
        ]}
    }}
])

Ale to nie działa w ten sposób, ponieważ $add oczekuje argumentów w przeciwieństwie do tablicy z dokumentu. Westchnienie! :(. Część rozumowania „zgodnie z projektem” może być argumentowana, że ​​„tylko dlatego”, że jest to tablica lub „lista” pojedynczych wartości przekazywanych z wyniku transformacji, nie jest „gwarantowane”, że są one faktycznie "prawidłowe" pojedyncze wartości liczbowe, których oczekuje operator. Przynajmniej nie przy aktualnie zaimplementowanych metodach "sprawdzania typu".

Oznacza to, że na razie musimy to zrobić:

db.collection.aggregate([
   { "$unwind": "$items" },
   { "$group": {
       "_id": "$_id",
        "total": { "$sum": "$items.value" }
   }}
])

A także niestety nie byłoby możliwości zastosowania takiego operatora grupującego do łączenia łańcuchów.

Więc możesz mieć nadzieję na jakąś zmianę w tej sprawie lub mieć nadzieję na jakąś zmianę, która pozwoli na zmianę zmiennej o zakresie zewnętrznym w zakresie $map działanie w jakiś sposób. Jeszcze lepiej nowy $join operacja byłaby również mile widziana. Ale te nie istnieją w chwili pisania i prawdopodobnie nie będą przez jakiś czas.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Jaka jest różnica między metodami insert(), insertOne() i insertMany()?

  2. Formatowanie ISODate z Mongodb

  3. mongodb TTL nie usuwa dokumentów

  4. Współpraca Sparka, Pythona i MongoDB

  5. MongoDB - Usuń dokument