মোঙ্গোডিবি'র cla দফা গ্যারান্টি অর্ডারে রয়েছে?


90

মঙ্গোডিবি-র $inধারাটি ব্যবহার করার সময়, ফিরে আসা দস্তাবেজের ক্রমটি কি সর্বদা অ্যারে যুক্তির ক্রমের সাথে মিলে যায়?


8
এই বৈশিষ্ট্যের জন্য মঙ্গোডিবি টিকিট
মিটার

উত্তর:


80

যেমনটি উল্লেখ করা হয়েছে, একটি ধারা $ এর অ্যারেতে যুক্তিগুলির ক্রম কীভাবে নথিগুলি পুনরুদ্ধার করা হয় তার ক্রম প্রতিফলিত করে না। অবশ্যই এটি প্রাকৃতিক আদেশ বা নির্বাচিত সূচক আদেশ দ্বারা প্রদর্শিত হবে।

আপনার যদি এই অর্ডার সংরক্ষণের প্রয়োজন হয় তবে আপনার কাছে মূলত দুটি বিকল্প রয়েছে।

সুতরাং বলুন যে আপনি _idআপনার দস্তাবেজের মানগুলির সাথে এমন একটি অ্যারের সাথে মিলছিলেন যা সেই $inহিসাবে পাস করা হবে [ 4, 2, 8 ]

সমষ্টি ব্যবহার করে পন্থা


var list = [ 4, 2, 8 ];

db.collection.aggregate([

    // Match the selected documents by "_id"
    { "$match": {
        "_id": { "$in": [ 4, 2, 8 ] },
    },

    // Project a "weight" to each document
    { "$project": {
        "weight": { "$cond": [
            { "$eq": [ "$_id", 4  ] },
            1,
            { "$cond": [
                { "$eq": [ "$_id", 2 ] },
                2,
                3
            ]}
        ]}
    }},

    // Sort the results
    { "$sort": { "weight": 1 } }

])

সুতরাং এটি প্রসারিত ফর্ম হবে। এখানে মূলত যা ঘটে তা হ'ল মানগুলির অ্যারে যেমন $inআপনার কাছে চলে যায় তেমনি $condমানগুলি পরীক্ষা করার জন্য একটি "নেস্টেড" স্টেটমেন্টও তৈরি করে উপযুক্ত ওজন নির্ধারণ করে। যেহেতু "ওজন" মান অ্যারের উপাদানগুলির ক্রমকে প্রতিফলিত করে, তারপরে প্রয়োজনীয় ফলাফল অনুসারে আপনার ফলাফল পেতে আপনি সেই মানটিকে একটি সাজানোর পর্যায়ে পাস করতে পারেন।

অবশ্যই আপনি কোডে পাইপলাইন স্টেটমেন্টটি "বিল্ড" করুন, অনেকটা এরকম:

var list = [ 4, 2, 8 ];

var stack = [];

for (var i = list.length - 1; i > 0; i--) {

    var rec = {
        "$cond": [
            { "$eq": [ "$_id", list[i-1] ] },
            i
        ]
    };

    if ( stack.length == 0 ) {
        rec["$cond"].push( i+1 );
    } else {
        var lval = stack.pop();
        rec["$cond"].push( lval );
    }

    stack.push( rec );

}

var pipeline = [
    { "$match": { "_id": { "$in": list } }},
    { "$project": { "weight": stack[0] }},
    { "$sort": { "weight": 1 } }
];

db.collection.aggregate( pipeline );

মানচিত্রের ব্যবহার ব্যবহার করুন ed


অবশ্যই যদি এটি সমস্ত আপনার সংবেদনশীলতার পক্ষে মনে হয় তবে আপনি মানচিত্রের ব্যবহার করে একই জিনিসটি করতে পারেন যা সহজ দেখায় তবে সম্ভবত কিছুটা ধীরে চলবে।

var list = [ 4, 2, 8 ];

db.collection.mapReduce(
    function () {
        var order = inputs.indexOf(this._id);
        emit( order, { doc: this } );
    },
    function() {},
    { 
        "out": { "inline": 1 },
        "query": { "_id": { "$in": list } },
        "scope": { "inputs": list } ,
        "finalize": function (key, value) {
            return value.doc;
        }
    }
)

এবং এটি মূলত নির্গত "কী" মানগুলিকে কীভাবে ইনপুট অ্যারেতে ঘটে তার "সূচী ক্রমে" থাকা নির্ভর করে values


সুতরাং সেগুলি হ'ল একটি ইনপুট তালিকার ক্রম বজায় রাখার আপনার উপায়গুলি $inযেখানে আপনি ইতিমধ্যে একটি নির্ধারিত ক্রমে সেই তালিকাটি রেখেছেন ।


4
দুর্দান্ত উত্তর। যাদের এটির প্রয়োজন তাদের জন্য এখানে
লরেন্স জোন্স

4
@ নীললুন আমি সামগ্রিক ব্যবহার করে এই পদ্ধতির চেষ্টা করেছিলাম, তবে আমি আইডিটির ওজনটি পেয়েছি। আপনি কীভাবে পোস্টগুলি (অবজেক্ট) পুনরুদ্ধার করবেন জানেন?
জুয়ানজো লাইনেজ রিচে

4
@NeilLunn আমি আসলে করেনি (এটা এখানে stackoverflow.com/questions/27525235/... ) কিন্তু মন্তব্য এখানে উল্লেখ ছিল, যদিও আমি আমার প্রশ্নের পোস্ট করার আগে এই চেক। আপনি কি আমাকে সেখানে সাহায্য করতে পারেন? ধন্যবাদ!
জুয়ানজো লায়েঞ্জ রিচে

4
জানুন এটি পুরানো, তবে ইনপুটস.আইডিএক্সঅফ () এর সাথে মেলে না কেন ডিবাগ করার জন্য আমি অনেক সময় নষ্ট করি __আইডি। আপনি যদি কেবল আইডির মানটি ফিরিয়ে দিচ্ছেন তবে আপনাকে এই বাক্য গঠনটি বেছে নিতে পারেন: obj.map = ফাংশন () {এর জন্য (var i = 0; i <ইনপুটস.লেন্থ; i++) {যদি (এটি)। _id.equals (ইনপুটস [i]) {ভের অর্ডার = আই; mit mit নির্গমন (আদেশ, {ডক: এটি}); };
নুবস্টার

4
আপনি যদি সমস্ত মূল ক্ষেত্রও পেতে চান তবে আপনি "$ প্রজেক্ট" এর পরিবর্তে "$ অ্যাডফিল্ডস" ব্যবহার করতে পারেন
Jodo

40

সমষ্টি ক্যোয়ারীটি ব্যবহারের অন্য উপায়টি কেবল মঙ্গোডিবি ভেরিয়ানের ক্ষেত্রে প্রযোজ্য > = 3.4 -

ক্রেডিট এই দুর্দান্ত ব্লগ পোস্টে যায়

এই ক্রমে আনার জন্য দস্তাবেজের উদাহরণ -

var order = [ "David", "Charlie", "Tess" ];

ক্যোয়ারী -

var query = [
             {$match: {name: {$in: order}}},
             {$addFields: {"__order": {$indexOfArray: [order, "$name" ]}}},
             {$sort: {"__order": 1}}
            ];

var result = db.users.aggregate(query);

ব্যবহৃত এই সমষ্টি অপারেটরদের ব্যাখ্যা করে পোস্টের আরেকটি উদ্ধৃতি -

"$ অ্যাডফিল্ডস" পর্যায়টি 3.4-এ নতুন এবং এটি অন্যান্য বিদ্যমান ক্ষেত্রগুলি না জেনে বিদ্যমান নথিতে নতুন ক্ষেত্র "" প্রজেক্ট "করতে দেয়। নতুন "$ indexOfArray" এক্সপ্রেশন একটি নির্দিষ্ট অ্যারেতে নির্দিষ্ট উপাদানটির অবস্থান প্রদান করে।

মূলত addFieldsঅপারেটরটি orderপ্রতিটি নথিতে এটি নতুন ক্ষেত্র সংযোজন করে যখন এটি এটি পায় এবং এই orderক্ষেত্রটি আমাদের সরবরাহ করা অ্যারের মূল ক্রমকে উপস্থাপন করে। তারপরে আমরা খালি এই ক্ষেত্রের উপর ভিত্তি করে নথিগুলি বাছাই করি।


কোয়েরিতে ভেরিয়েবল হিসাবে অর্ডার অ্যারে সংরক্ষণ করার কোনও উপায় আছে তাই যদি অ্যারে বড় হয় তবে আমাদের কাছে একই অ্যারের এই বিশাল কোয়েরিটি দু'বার নেই?
ইথান এসকে

27

আপনি যদি ব্যবহার করতে না চান তবে aggregateঅন্য সমাধানটি হ'ল findডক ফলাফলের ক্লায়েন্ট-সাইডটি ব্যবহার করে সারণি করা array#sort:

$inমানগুলি যদি সংখ্যার মতো আদিম ধরণের হয় তবে আপনি এই জাতীয় একটি পদ্ধতির ব্যবহার করতে পারেন:

var ids = [4, 2, 8, 1, 9, 3, 5, 6];
MyModel.find({ _id: { $in: ids } }).exec(function(err, docs) {
    docs.sort(function(a, b) {
        // Sort docs by the order of their _id values in ids.
        return ids.indexOf(a._id) - ids.indexOf(b._id);
    });
});

যদি $inমান মত অ আদিম ধরনের হয় ObjectIdএস, আরেকটি পন্থা হিসাবে প্রয়োজন বোধ করা হয় indexOfযে ক্ষেত্রে রেফারেন্স দ্বারা তুলনা করা হয়।

আপনি যদি নোড.জেএস ৪.x + ব্যবহার করছেন তবে আপনি এই ফাংশনটি পরিবর্তন করে এটি পরিচালনা করতে Array#findIndexএবং ObjectID#equalsপরিচালনা করতে পারেন sort:

docs.sort((a, b) => ids.findIndex(id => a._id.equals(id)) - 
                    ids.findIndex(id => b._id.equals(id)));

অথবা যে কোনও নোড.জেএস সংস্করণ সহ আন্ডারস্কোর / লোড্যাশ সহ findIndex:

docs.sort(function (a, b) {
    return _.findIndex(ids, function (id) { return a._id.equals(id); }) -
           _.findIndex(ids, function (id) { return b._id.equals(id); });
});

সমান ফাংশন আইডি 'রিটার্ন a.equals (id);' এর সাথে কোনও আইডি সম্পত্তিকে তুলনা করতে কীভাবে জানতে পারে, সেই মডেলের জন্য ফিরিয়ে দেওয়া সমস্ত সম্পত্তি একটি আওতায় আনতে পারে?
lboyel

4
@ এলবয়েল আমার বোঝার অর্থ এই চতুর নয় :-), কিন্তু এটি কাজ করেছিল কারণ এটি মঙ্গুজকে ডকের ক্ষেত্রের Document#equalsসাথে তুলনা করার জন্য ব্যবহার করছিল _id_idতুলনা সুস্পষ্ট করতে আপডেট হয়েছে । জিজ্ঞাসা করার জন্য ধন্যবাদ.
জনিএইচকে

6

অনুরূপ JonnyHK এর সমাধান, আপনি নথি থেকে প্রত্যাগত পুনর্বিন্যাস করতে findআপনার ক্লায়েন্ট মধ্যে একটি সমন্বয় সঙ্গে (যদি আপনার ক্লায়েন্ট জাভাস্ক্রিপ্ট হয়) mapএবং Array.prototype.findECMAScript 2015 সালে ফাংশন:

Collection.find({ _id: { $in: idArray } }).toArray(function(err, res) {

    var orderedResults = idArray.map(function(id) {
        return res.find(function(document) {
            return document._id.equals(id);
        });
    });

});

কয়েকটি নোট:

  • উপরের কোডটি মঙ্গো নোড ড্রাইভার ব্যবহার করছে না মঙ্গুজকে
  • এর idArrayএকটি অ্যারেObjectId
  • আমি এই পদ্ধতির বনাম বাছাইয়ের পদ্ধতিটির পরীক্ষা করিনি, তবে আপনাকে যদি প্রতিটি ফিরে আসা আইটেম (যা সাধারণভাবে সাধারণ) ব্যবহার করতে হয় তবে mapআপনার কোডটি সহজ করার জন্য আপনি কলব্যাকে এটি করতে পারেন ।

চলমান সময় হ'ল ও (এন * এন), কারণ অভ্যন্তরের findঅ্যারের প্রতিটি উপাদান (বাহির থেকে map) জন্য অ্যারেটিকে ঘুরিয়ে দেয় । এটি মারাত্মকভাবে অক্ষম, কারণ এখানে একটি সন্ধানের টেবিল ব্যবহার করে একটি ও (এন) সমাধান রয়েছে।
curran

5

আমি জানি এই প্রশ্নটি মঙ্গুজ জেএস কাঠামোর সাথে সম্পর্কিত, তবে সদৃশটি জেনেরিক, সুতরাং আমি আশা করি এখানে পাইথন (পাইমঙ্গো) সমাধান পোস্ট করা ভাল।

things = list(db.things.find({'_id': {'$in': id_array}}))
things.sort(key=lambda thing: id_array.index(thing['_id']))
# things are now sorted according to id_array order

5

মঙ্গো অ্যারে ফেরত দেওয়ার পরে ফলাফল অর্ডার করার একটি সহজ উপায় হ'ল কী হিসাবে আইডি দিয়ে কোনও বস্তু তৈরি করা এবং তারপরে সঠিকভাবে অর্ডার করা একটি অ্যারে ফিরিয়ে দেওয়ার জন্য প্রদত্ত _ID এর উপরে ম্যাপ করা।

async function batchUsers(Users, keys) {
  const unorderedUsers = await Users.find({_id: {$in: keys}}).toArray()
  let obj = {}
  unorderedUsers.forEach(x => obj[x._id]=x)
  const ordered = keys.map(key => obj[key])
  return ordered
}

4
এটি আমার যা প্রয়োজন ঠিক তা করে এবং শীর্ষ মন্তব্যের চেয়ে অনেক সহজ।
ডায়ারব্রু

@ আইডিআরব্রু এই সমাধানটি কেবলমাত্র এমন সমস্ত প্রশ্নের জন্য কাজ করে যা সমস্ত দস্তাবেজগুলি (সীমা ছাড়াই বা এড়ানো ছাড়াই) আনে। শীর্ষ মন্তব্যটি আরও জটিল তবে প্রতিটি দৃশ্যের জন্য কাজ করে।
marian2js

3

সর্বদা? কখনই না। ক্রমটি সর্বদা একই থাকে: অপরিজ্ঞাত (সম্ভবত দৈহিক ক্রম যেখানে নথিগুলি সংরক্ষণ করা হয়)। যদি আপনি এটি বাছাই না করে।


$naturalস্বাভাবিকভাবে অর্ডার করুন যা
শারীরিকের

1

আমি জানি এটি একটি পুরানো থ্রেড, তবে আপনি যদি অ্যারেতে আইডির মানটি ফিরিয়ে দিচ্ছেন তবে আপনাকে এই বাক্য গঠনটি বেছে নিতে পারেন। যেহেতু আমি মোঙ্গো অবজেক্টআইডি ফর্ম্যাটটির সাথে মেলানোর জন্য সূচিপত্রের মান পেতে পারি না।

  obj.map = function() {
    for(var i = 0; i < inputs.length; i++){
      if(this._id.equals(inputs[i])) {
        var order = i;
      }
    }
    emit(order, {doc: this});
  };

'অবজেক্টআইডি ()' র‍্যাপারকে অন্তর্ভুক্ত না করে কীভাবে মঙ্গো অবজেক্টআইডি। স্ট্রিংকে রূপান্তর করবেন - কেবল মান?


0

আপনি $ বা ধারা দিয়ে অর্ডার গ্যারান্টি দিতে পারেন।

$or: [ _ids.map(_id => ({_id}))]পরিবর্তে ব্যবহার করুন।


4
$orকার্যসংক্রান্ত কাজ করেননি v2.6 যেহেতু
জনিএইচকে

0

মঙ্গো থেকে ফলাফল পুনরুদ্ধার করার পরে এটি একটি কোড সমাধান। সূচক সঞ্চয় করতে মানচিত্র ব্যবহার করা এবং তারপরে মানগুলি অদলবদল করা।

catDetails := make([]CategoryDetail, 0)
err = sess.DB(mdb).C("category").
    Find(bson.M{
    "_id":       bson.M{"$in": path},
    "is_active": 1,
    "name":      bson.M{"$ne": ""},
    "url.path":  bson.M{"$exists": true, "$ne": ""},
}).
    Select(
    bson.M{
        "is_active": 1,
        "name":      1,
        "url.path":  1,
    }).All(&catDetails)

if err != nil{
    return 
}
categoryOrderMap := make(map[int]int)

for index, v := range catDetails {
    categoryOrderMap[v.Id] = index
}

counter := 0
for i := 0; counter < len(categoryOrderMap); i++ {
    if catId := int(path[i].(float64)); catId > 0 {
        fmt.Println("cat", catId)
        if swapIndex, exists := categoryOrderMap[catId]; exists {
            if counter != swapIndex {
                catDetails[swapIndex], catDetails[counter] = catDetails[counter], catDetails[swapIndex]
                categoryOrderMap[catId] = counter
                categoryOrderMap[catDetails[swapIndex].Id] = swapIndex
            }
            counter++
        }
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.