webentwicklung-frage-antwort-db.com.de

wie konvertiert man String in numerische Werte in Mongodb?

Ich versuche, eine Zeichenfolge, die einen numerischen Wert enthält, in eine Gesamtabfrage in MongoDB in ihren Wert umzuwandeln.

Beispiel eines Dokuments

{
"_id": ObjectId("5522XXXXXXXXXXXX"),
   "Date": "2015-04-05",
   "PartnerID": "123456",
   "moop": "1234" 
}

Beispiel für die Aggregatabfrage, die ich verwende

{
    aggregate: 'my_collection',
    pipeline: [
         {$match: {
             Date : 
                  {$gt:'2015-04-01', 
                  $lt: '2015-04-05'
                  }}
             },
         {$group:
             {_id: "$PartnerID",
              total:{$sum:'$moop'}
             }}]}

wo die Ergebnisse sind 

{
   "result": [
     {
       "_id": "123456",
       "total": NumberInt(0) 
    }
}

Wie kann man den String in seinen numerischen Wert konvertieren?

28
Naftsen

Die MongoDB-Aggregation darf den vorhandenen Datentyp der angegebenen Felder nicht ändern. In diesem Fall sollten Sie Programmcode erstellen, um string in int zu konvertieren. Überprüfen Sie den Code unten 

db.collectionName.find().forEach(function(data) {
    db.collectionName.update({
        "_id": data._id,
        "moop": data.moop
    }, {
        "$set": {
            "PartnerID": parseInt(data.PartnerID)
        }
    });
})

Wenn die Größe Ihrer Sammlungen größer als das obige Skript ist, wird die Leistung verlangsamt. Für Perfomace Mongo sind Mongo-Bulk -Operationen erforderlich. Bei Mongo-Bulk-Operationen wurde auch der Datentyp aktualisiert

var bulk = db.collectionName.initializeOrderedBulkOp();
var counter = 0;
db.collectionName.find().forEach(function(data) {
    var updoc = {
        "$set": {}
    };
    var myKey = "PartnerID";
    updoc["$set"][myKey] = parseInt(data.PartnerID);
    // queue the update
    bulk.find({
        "_id": data._id
    }).update(updoc);
    counter++;
    // Drain and re-initialize every 1000 update statements
    if (counter % 1000 == 0) {
        bulk.execute();
        bulk = db.collectionName.initializeOrderedBulkOp();
    }
    })
    // Add the rest in the queue
if (counter % 1000 != 0) bulk.execute();

Dies reduziert im Wesentlichen die Anzahl der an den Server gesendeten Operationsanweisungen auf ein einmaliges Senden von jeweils 1000 in der Warteschlange befindlichen Operationen. 

26
Yogesh

Sie können den String-Datentyp leicht in einen numerischen Datentyp konvertieren.

Vergessen Sie nicht, collectionName & FieldName . Für Beispiel zu ändern: CollectionNmae: Users & FieldName: Contactno.

Versuchen Sie diese Abfrage ..

db.collectionName.find().forEach( function (x) {
x.FieldName = parseInt(x.FieldName);
db.collectionName.save(x);
});
12
Amarendra Kumar

Irgendwann habe ich gebraucht 

db.my_collection.find({moop: {$exists: true}}).forEach(function(obj) {
    obj.moop = new NumberInt(obj.moop);
    db.my_collection.save(obj);
});

moop von string in eine ganze Zahl in my_collection umwandeln, gemäß dem Beispiel in Simones Antwort MongoDB: Wie kann man den Typ eines Feldes ändern? .

9
Naftsen

Verwenden von MongoDB 4.0 und neuer

Sie haben zwei Optionen, d. H. $toInt oder $convert. Führen Sie das folgende Beispiel aus, indem Sie $toInt verwenden:

filterDateStage = {
    '$match': {
        'Date': {
            '$gt': '2015-04-01', 
            '$lt': '2015-04-05'
        }
    }
};

groupStage = {
    '$group': {
        '_id': '$PartnerID',
        'total': { '$sum': { '$toInt': '$moop' } }
    }
};

db.getCollection('my_collection').aggregate([
   filterDateStage,
   groupStage
])

Wenn bei der Konvertierungsoperation ein Fehler auftritt, wird die Aggregationsoperation angehalten und ein Fehler ausgegeben. Um dieses Verhalten zu überschreiben, verwenden Sie stattdessen $convert.

Verwenden von $convert

groupStage = {
    '$group': {
        '_id': '$PartnerID',
        'total': { 
            '$sum': { 
                '$convert': { 'input': '$moop', 'to': 'int' }
            } 
        }
    }
};

Map verwenden/reduzieren

Mit map/verkleinern können Sie Javascript-Funktionen wie parseInt() verwenden, um die Konvertierung durchzuführen. Als ein Beispiel könnten Sie die Map-Funktion definieren, um jedes Eingabedokument zu verarbeiten: In der Funktion bezieht sich this auf das Dokument, das die Map-Reduktions-Operation verarbeitet. Die Funktion ordnet den konvertierten moop-Zeichenfolgenwert dem PartnerID für jedes Dokument zu und gibt das PartnerID- und das konvertierte moop-Paar aus. Hier kann die native Javascript-Funktion parseInt() angewendet werden:

var mapper = function () {
    var x = parseInt(this.moop);
    emit(this.PartnerID, x);
};

Als Nächstes definieren Sie die entsprechende Verringerungsfunktion mit den zwei Argumenten keyCustId und valuesMoop. valuesMoop ist ein Array, dessen Elemente die Ganzzahl moop-Werte sind, die von der map-Funktion ausgegeben und nach keyPartnerID..__ gruppiert werden. Die Funktion reduziert das valuesMoop-Array auf die Summe seiner Elemente.

var reducer = function(keyPartnerID, valuesMoop) {
                  return Array.sum(valuesMoop);
              };

db.collection.mapReduce(
    mapper,
    reducer,
    {
        out : "example_results",
        query: { 
            Date: {
                $gt: "2015-04-01", 
                $lt: "2015-04-05"
            }
        }       
    }
 );

 db.example_results.find(function (err, docs) {
    if(err) console.log(err);
    console.log(JSON.stringify(docs));
 });

Zum Beispiel mit der folgenden Beispielsammlung von Dokumenten:

/* 0 */
{
    "_id" : ObjectId("550c00f81bcc15211016699b"),
    "Date" : "2015-04-04",
    "PartnerID" : "123456",
    "moop" : "1234"
}

/* 1 */
{
    "_id" : ObjectId("550c00f81bcc15211016699c"),
    "Date" : "2015-04-03",
    "PartnerID" : "123456",
    "moop" : "24"
}

/* 2 */
{
    "_id" : ObjectId("550c00f81bcc15211016699d"),
    "Date" : "2015-04-02",
    "PartnerID" : "123457",
    "moop" : "21"
}

/* 3 */
{
    "_id" : ObjectId("550c00f81bcc15211016699e"),
    "Date" : "2015-04-02",
    "PartnerID" : "123457",
    "moop" : "8"
}

Die obige Map/Reduce-Operation speichert die Ergebnisse in der example_results-Sammlung, und der Shell-Befehl db.example_results.find() gibt Folgendes aus:

/* 0 */
{
    "_id" : "123456",
    "value" : 1258
}

/* 1 */
{
    "_id" : "123457",
    "value" : 29
}
6
chridam

Hier ist eine reine MongoDB-basierte Lösung für dieses Problem, die ich gerade zum Spaß geschrieben habe. Es ist praktisch ein serverseitiger String-to-Number-Parser, der positive und negative Zahlen sowie Dezimalzahlen unterstützt:

db.collection.aggregate({
    $addFields: {
        "moop": {
            $reduce: {
                "input": {
                    $map: { // split string into char array so we can loop over individual characters
                        "input": {
                            $range: [ 0, { $strLenCP: "$moop" } ] // using an array of all numbers from 0 to the length of the string
                        },
                        "in":{
                            $substrCP: [ "$moop", "$$this", 1 ] // return the nth character as the mapped value for the current index
                        }
                    }
                },
                "initialValue": { // initialize the parser with a 0 value
                    "n": 0, // the current number
                    "sign": 1, // used for positive/negative numbers
                    "div": null, // used for shifting on the right side of the decimal separator "."
                    "mult": 10 // used for shifting on the left side of the decimal separator "."
                }, // start with a zero
                "in": {
                    $let: {
                        "vars": {
                            "n": {
                                $switch: { // char-to-number mapping
                                    branches: [
                                        { "case": { $eq: [ "$$this", "1" ] }, "then": 1 },
                                        { "case": { $eq: [ "$$this", "2" ] }, "then": 2 },
                                        { "case": { $eq: [ "$$this", "3" ] }, "then": 3 },
                                        { "case": { $eq: [ "$$this", "4" ] }, "then": 4 },
                                        { "case": { $eq: [ "$$this", "5" ] }, "then": 5 },
                                        { "case": { $eq: [ "$$this", "6" ] }, "then": 6 },
                                        { "case": { $eq: [ "$$this", "7" ] }, "then": 7 },
                                        { "case": { $eq: [ "$$this", "8" ] }, "then": 8 },
                                        { "case": { $eq: [ "$$this", "9" ] }, "then": 9 },
                                        { "case": { $eq: [ "$$this", "0" ] }, "then": 0 },
                                        { "case": { $and: [ { $eq: [ "$$this", "-" ] }, { $eq: [ "$$value.n", 0 ] } ] }, "then": "-" }, // we allow a minus sign at the start
                                        { "case": { $eq: [ "$$this", "." ] }, "then": "." }
                                    ],
                                    default: null // marker to skip the current character
                                } 
                            }
                        },
                        "in": {
                            $switch: {
                                "branches": [
                                    {
                                        "case": { $eq: [ "$$n", "-" ] },
                                        "then": { // handle negative numbers
                                            "sign": -1, // set sign to -1, the rest stays untouched
                                            "n": "$$value.n",
                                            "div": "$$value.div",
                                            "mult": "$$value.mult",
                                        },
                                    },
                                    {
                                        "case": { $eq: [ "$$n", null ] }, // null is the "ignore this character" marker
                                        "then": "$$value" // no change to current value
                                    }, 
                                    {
                                        "case": { $eq: [ "$$n", "." ] },
                                        "then": { // handle decimals
                                            "n": "$$value.n",
                                            "sign": "$$value.sign",
                                            "div": 10, // from the decimal separator "." onwards, we start dividing new numbers by some divisor which starts at 10 initially
                                            "mult": 1, // and we stop multiplying the current value by ten
                                        },
                                    }, 
                                ],
                                "default": {
                                    "n": {
                                        $add: [
                                            { $multiply: [ "$$value.n", "$$value.mult" ] }, // multiply the already parsed number by 10 because we're moving one step to the right or by one once we're hitting the decimals section
                                            { $divide: [ "$$n", { $ifNull: [ "$$value.div", 1 ] } ] } // add the respective numerical value of what we look at currently, potentially divided by a divisor
                                        ]
                                    },
                                    "sign": "$$value.sign",
                                    "div": { $multiply: [ "$$value.div" , 10 ] },
                                    "mult": "$$value.mult"
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}, {
    $addFields: { // fix sign
        "moop": { $multiply: [ "$moop.n", "$moop.sign" ] }
    }
})

Ich werbe das sicherlich nicht als Knie oder etwas anderes der Biene und es könnte schwerwiegende Auswirkungen auf die Leistung für größere Datensätze im Vergleich zu einer Client-basierten Lösung haben.

Die obige Pipeline transformiert die folgenden Dokumente:

{ "moop": "12345" } --> { "moop": 12345 }

und

{ "moop": "123.45" } --> { "moop": 123.45 }

und

{ "moop": "-123.45" } --> { "moop": -123.45 }

und

{ "moop": "2018-01-03" } --> { "moop": 20180103.0 }
4
dnickless

String kann in MongoDB v4.0 mit $ toInt operator in Zahlen umgewandelt werden. In diesem Fall

db.col.aggregate([
    {
        $project: {
            _id: 0,
            moopNumber: { $toInt: "$moop" }
        }
    }
])

ausgänge:

{ "moopNumber" : 1234 }
4
mickl

Drei Dinge müssen beachtet werden:

  1. parseInt () speichert doppelten Datentyp in mongodb. Bitte verwenden Sie eine neue NumberInt (Zeichenfolge).
  2. im Mongo Shell-Befehl für die Massenverwendung funktioniert der Ertrag nicht. Bitte addieren Sie NICHT "Ertrag".
  3. Wenn Sie die Zeichenfolge bereits per parseInt () in double ändern. Anscheinend haben Sie keine Möglichkeit, den Typ direkt in int zu ändern. Die Lösung ist etwas verdrahtet: Ändern Sie zuerst double in string und ändern Sie sie dann durch new NumberInt () wieder in int.
3
Bing Wu

Collation ist das, was Sie brauchen:

db.collectionName.find().sort({PartnerID: 1}).collation({locale: "en_US", numericOrdering: true})
1
Dan Loughney

Es sollte gerettet werden. Es sollte so sein:

     db. my_collection.find({}).forEach(function(theCollection) {
         theCollection.moop = parseInt(theCollection.moop);
        db.my_collection.save(theCollection);
     });
1
Reza

Versuchen:

"TimeStamp":{$toDecimal: { $toDate:"$Datum"}}
0
Dalibor Adamec

Wenn Sie alle Dokumente zusammen bearbeiten können:

"TimeStamp": {$toDecimal: {$toDate: "$Your Date"}}

Und für den Client stellen Sie die Abfrage ein:

Date.parse("Your date".toISOString())

Deshalb arbeiten Sie mit ISODate zusammen.

0
Dalibor Adamec