2011-06-15 17 views
31

Come si fa a fare l'equivalente diCome trovare valore minimo in MongoDB

SELECT 
    MIN(Id) AS MinId 
FROM 
    Table 

in MongoDB. Sembra che dovrò usare MapReduce ma non riesco a trovare alcun esempio che mostri come farlo.

Grazie.

risposta

55

È possibile utilizzare una combinazione di sort e limit per emulare min:

> db.foo.insert({a: 1}) 
> db.foo.insert({a: 2}) 
> db.foo.insert({a: 3}) 
> db.foo.find().sort({a: 1}).limit(1) 
{ "_id" : ObjectId("4df8d4a5957c623adae2ab7e"), "a" : 1 } 

sort({a: 1}) è un ordine crescente (minimo-prima) sul campo a, e poi restituire solo il primo documento, che sarà essere il valore minimo per quel campo

MODIFICA: nota che questo è scritto nella shell mongo, ma puoi fare la stessa cosa da C# o qualsiasi altra lingua usando i metodi appropriati del driver.

+5

Nota: probabilmente si vorrà un indice su un {1} per ogni grande insieme di dati. –

+2

è ancora il modo ottimale per ottenere un valore minimo? – clifgray

+2

Ora è possibile utilizzare il framework Aggregate per ottenere questo risultato. Vedi la risposta qui sotto da wanghao. db.myCollection.aggregate ( [ { $ gruppo: { _id: {}, MINPRICE: {$ min: "$ prezzo"}} } ] ); – Waqas

8

Voglio solo mostrare come può essere fatto con il driver C# ufficiale (da una domanda su mongodb csharp) con un miglioramento: sto caricando solo un campo, ma non tutto il documento se voglio solo trovare il valore Min di quel campo. Qui è completo banco di prova:

[TestMethod] 
public void Test() 
{ 
    var _mongoServer = MongoServer.Create("mongodb://localhost:27020"); 
    var database = _mongoServer.GetDatabase("StackoverflowExamples"); 
    var col = database.GetCollection("items"); 

    //Add test data 
    col.Insert(new Item() { IntValue = 1, SomeOtherField = "Test" }); 
    col.Insert(new Item() { IntValue = 2 }); 
    col.Insert(new Item() { IntValue = 3 }); 
    col.Insert(new Item() { IntValue = 4 }); 

    var item = col.FindAs<Item>(Query.And()) 
    .SetSortOrder(SortBy.Ascending("IntValue")) 
    .SetLimit(1) 
    .SetFields("IntValue") //here i loading only field that i need 
    .Single(); 
    var minValue = item.IntValue; 

    //Check that we found min value of IntValue field 
    Assert.AreEqual(1, minValue); 
    //Check that other fields are null in the document 
    Assert.IsNull(item.SomeOtherField); 
    col.RemoveAll(); 
} 

E Item classe:

public class Item 
{ 
    public Item() 
    { 
    Id = ObjectId.GenerateNewId(); 
    } 

    [BsonId] 
    public ObjectId Id { get; set; } 
    public int IntValue { get; set; } 
    public string SomeOtherField { get; set; } 
} 

Aggiornamento: sempre cercando di avvicinarsi ulteriormente, così, qui è il metodo estensione per la ricerca di valore minimo all'interno della collezione:

public static class MongodbExtentions 
{ 
    public static int FindMinValue(this MongoCollection collection, string fieldName) 
    { 
     var cursor = collection.FindAs<BsonDocument>(Query.And()) 
        .SetSortOrder(SortBy.Ascending(fieldName)) 
        .SetLimit(1) 
        .SetFields(fieldName); 

     var totalItemsCount = cursor.Count(); 

     if (totalItemsCount == 0) 
      throw new Exception("Collection is empty"); 

     var item = cursor.Single(); 

     if (!item.Contains(fieldName)) 
      throw new Exception(String.Format("Field '{0}' can't be find within '{1}' collection", fieldName, collection.Name)); 

     return item.GetValue(fieldName).AsInt32; // here we can also check for if it can be parsed 
    } 
} 

Così sopra il caso di test con questo metodo di estensione può essere riscritto in questo modo:

[TestMethod] 
public void Test() 
{ 
    var _mongoServer = MongoServer.Create("mongodb://localhost:27020"); 
    var database = _mongoServer.GetDatabase("StackoverflowExamples"); 
    var col = database.GetCollection("items"); 

    var minValue = col.FindMinValue("IntValue"); 

    Assert.AreEqual(1, minValue); 
    col.RemoveAll(); 
} 

Spero che qualcuno lo userà;).

+0

Grazie! Stavo per scrivere il codice per il driver C# – atbebtg

+0

@atbebtg: sei il benvenuto. Solo un secondo fa ho aggiornato la mia risposta, quindi ho creato il metodo di estensione per trovare il valore minimo;) –

+0

@Andred Orsich: Wow! Non so cos'altro dire. Ancora una volta grazie! Non preoccuparti, userò sicuramente quella funzione :) – atbebtg

10

Il primo

db.sales.insert([ 
    { "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-01-01T08:00:00Z") }, 
    { "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-02-03T09:00:00Z") }, 
    { "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-03T09:05:00Z") }, 
    { "_id" : 4, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-02-15T08:00:00Z") }, 
    { "_id" : 5, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T09:05:00Z") } 
    ]) 

Il secondo, trovare il valore minimo

db.sales.aggregate(
    [ 
    { 
     $group: 
     { 
     _id: {}, 
     minPrice: { $min: "$price" } 
     } 
    } 
    ] 
); 

risultato è

{ "_id" : { }, "minPrice" : 5 } 

È inoltre possibile utilizzare la funzione min come questo.

db.sales.aggregate(
    [ 
     { 
     $group: 
     { 
      _id: "$item", 
      minQuantity: { $min: "$quantity" } 
     } 
     } 
    ] 
) 

risultato sono

{ "_id" : "xyz", "minQuantity" : 5 } 
{ "_id" : "jkl", "minQuantity" : 1 } 
{ "_id" : "abc", "minQuantity" : 2 } 

$ min è un operatore di accumulo disponibile solo nella fase $ gruppo.

UPDATE: Modificato nella versione 3.2: $ min è disponibile nelle fasi $ gruppo e $ di progetto. Nelle versioni precedenti di MongoDB, $ min è disponibile solo nella fase $ gruppo.

click here for more help

+1

Falso: può essere utilizzato nella fase '$ project'. Controlla il documento a cui ti colleghi. – catalandres

Problemi correlati