2014-04-12 5 views
6

Wprowadzam sposób, aby użytkownicy mogli zmienić swoją nazwę użytkownika w aplikacji Meteor, którą piszę. Przed zaakceptowaniem zmian chcę sprawdzić, czy nazwa użytkownika już istnieje. Nazwy użytkowników mogą zawierać wielkie i małe litery, ale muszą być unikalnymi nazwami niezależnie od wielkości liter. Na przykład bob i Bob nie mogą istnieć razem.Meteor: jak zrobić niewrażliwy na wielkość kolekcji collection.findOne()?

Problem polega na tym, że nie potrafię wymyślić, jak wykonać collection.findOne(), który nie uwzględnia wielkości liter. Na przykład, że mam kolekcję o nazwie Profile, chciałbym być w stanie zrobić coś takiego:

newName = "bob"; 

//Assume "Bob" exists as a username in the Profiles collection; 

var isAlreadyRegistered = Profiles.findOne({"username": newName}); 

if (isAlreadyRegistered == null) { 
    saveUsername(); 
}; 

Odpowiedz

12

Twój może korzystać regular expression.

var isAlreadyRegistered = Profiles.findOne({"username": /^newName$/i }); 

Można też zapytać jak to również:

var isAlreadyRegistered = Profiles.findOne({ "username" : { 
        $regex : new RegExp(newName, "i") } } 
       ); 
+1

Świetna odpowiedź, ale zastanawiam się, dlaczego twój pierwszy przykład nie działa dla mnie, podczas gdy drugi robi. – adrianmc

2

Istnieją dwa sposoby i może się wahać co do najlepszej metody dla ciebie, ale oba są dość straszne faktycznie od MongoDB nie przypadek „wrażliwe” dopasowanie:

pierwsze podejście jest użycie $regex:

Profiles.findOne({ "username": { 
    "$regex": "^" + newName + "\\b", "$options": "i" 
}}) 

który pasuje do słowa i tylko słowa dokładnie od początku łańcucha w przypadku, niewrażliwego sposób. Problem polega na tym, że skanujesz indeks.

Drugie podejście do projektu przy użyciu agregatu:

db.collection("profiles").aggregate([ 
    { "$project": { 
     "username": 1, 
     "lower": { "$toLower": "$username" } 
    }}, 
    { "$match": { 
     "username": newName 
    }} 
]) 

I to zrobić, gdzie oczywiście newName już konwertowane na małe litery.

Problem polega na tym, że będzie nad wszystkim, co jest w przygotowaniu, będzie $project. Ale może się przydać, jeśli najpierw będziesz mógł $match.

Oczywiście myślę, że aggregate jest dostępna tylko po stronie serwera, a nie przez Minimongo, więc nie jest to do rozważenia.

+0

Wierzę, że to powiedziałem i stwierdziłem, że może to wykorzystać na serwerze w ramach własnej metody. –

+0

@AndrewMao dla dobra wszystkich czytelników i dla ciebie, to stwierdzenie jest fałszywe.Wszystkie implementacje frameworków w pewnym momencie wykorzystują i umożliwiają dostęp do podstawowego sterownika i jego metod, więc pobierając natywny obiekt kolekcji, zawsze powinieneś być w stanie uzyskać tę metodę, a także ponieważ większość frameworków zapewnia przynajmniej interfejs "runCommand" w jakiejś formie można to zrobić w ten sposób. Wszystkie metody MongoDB w sterownikach są faktycznie realizowane w ten sposób. Więc niezależnie od składni wywołującej nie powinieneś mówić, że id nie jest dostępny. –

1

Jako rozwiązanie twojego podstawowego przypadku użycia sugeruję użycie dwóch pól do zapisania nazwy użytkownika zamiast jednej.

W wbudowanym polu nazwy użytkownika należy zapisać małą nazwę użytkownika. Drugie, dodatkowe pole przechowuje oryginalną wersję z rozróżnianiem wielkości liter.

Wyszukiwania będą prowadzone przed polem "nazwa użytkownika" z małymi kryteriami wyszukiwania, jak również przed użyciem.

+0

Zgodnie z ogólną przesłanką tego, co ** należy ** zrobić. Jesteś bardzo poprawny, ponieważ musi istnieć pole, które faktycznie ma małą wartość w dokumencie i jest indeksowane. Ale inne opcje istnieją tylko jako dowody, że faktycznie istnieją ** sposoby, aby to zrobić, a nawet "w locie", które często są pomijane. –

+1

Tak, jest to jeden z tych interesujących przypadków, w których pytanie dotyczy czegoś konkretnego, na które istnieją dobre odpowiedzi, ale faktyczna najlepsza praktyka rozwiązania problemu leżącego u podstaw problemu nie została faktycznie zadana. – alanning

Powiązane problemy