মঙ্গোডিবি-র $inধারাটি ব্যবহার করার সময়, ফিরে আসা দস্তাবেজের ক্রমটি কি সর্বদা অ্যারে যুক্তির ক্রমের সাথে মিলে যায়?
মঙ্গোডিবি-র $inধারাটি ব্যবহার করার সময়, ফিরে আসা দস্তাবেজের ক্রমটি কি সর্বদা অ্যারে যুক্তির ক্রমের সাথে মিলে যায়?
উত্তর:
যেমনটি উল্লেখ করা হয়েছে, একটি ধারা $ এর অ্যারেতে যুক্তিগুলির ক্রম কীভাবে নথিগুলি পুনরুদ্ধার করা হয় তার ক্রম প্রতিফলিত করে না। অবশ্যই এটি প্রাকৃতিক আদেশ বা নির্বাচিত সূচক আদেশ দ্বারা প্রদর্শিত হবে।
আপনার যদি এই অর্ডার সংরক্ষণের প্রয়োজন হয় তবে আপনার কাছে মূলত দুটি বিকল্প রয়েছে।
সুতরাং বলুন যে আপনি _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 );
অবশ্যই যদি এটি সমস্ত আপনার সংবেদনশীলতার পক্ষে মনে হয় তবে আপনি মানচিত্রের ব্যবহার করে একই জিনিসটি করতে পারেন যা সহজ দেখায় তবে সম্ভবত কিছুটা ধীরে চলবে।
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যেখানে আপনি ইতিমধ্যে একটি নির্ধারিত ক্রমে সেই তালিকাটি রেখেছেন ।
সমষ্টি ক্যোয়ারীটি ব্যবহারের অন্য উপায়টি কেবল মঙ্গোডিবি ভেরিয়ানের ক্ষেত্রে প্রযোজ্য > = 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ক্ষেত্রটি আমাদের সরবরাহ করা অ্যারের মূল ক্রমকে উপস্থাপন করে। তারপরে আমরা খালি এই ক্ষেত্রের উপর ভিত্তি করে নথিগুলি বাছাই করি।
আপনি যদি ব্যবহার করতে না চান তবে 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); });
});
Document#equalsসাথে তুলনা করার জন্য ব্যবহার করছিল _id। _idতুলনা সুস্পষ্ট করতে আপডেট হয়েছে । জিজ্ঞাসা করার জন্য ধন্যবাদ.
অনুরূপ 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একটি অ্যারেObjectIdmapআপনার কোডটি সহজ করার জন্য আপনি কলব্যাকে এটি করতে পারেন ।findঅ্যারের প্রতিটি উপাদান (বাহির থেকে map) জন্য অ্যারেটিকে ঘুরিয়ে দেয় । এটি মারাত্মকভাবে অক্ষম, কারণ এখানে একটি সন্ধানের টেবিল ব্যবহার করে একটি ও (এন) সমাধান রয়েছে।
আমি জানি এই প্রশ্নটি মঙ্গুজ জেএস কাঠামোর সাথে সম্পর্কিত, তবে সদৃশটি জেনেরিক, সুতরাং আমি আশা করি এখানে পাইথন (পাইমঙ্গো) সমাধান পোস্ট করা ভাল।
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
মঙ্গো অ্যারে ফেরত দেওয়ার পরে ফলাফল অর্ডার করার একটি সহজ উপায় হ'ল কী হিসাবে আইডি দিয়ে কোনও বস্তু তৈরি করা এবং তারপরে সঠিকভাবে অর্ডার করা একটি অ্যারে ফিরিয়ে দেওয়ার জন্য প্রদত্ত _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
}
আমি জানি এটি একটি পুরানো থ্রেড, তবে আপনি যদি অ্যারেতে আইডির মানটি ফিরিয়ে দিচ্ছেন তবে আপনাকে এই বাক্য গঠনটি বেছে নিতে পারেন। যেহেতু আমি মোঙ্গো অবজেক্টআইডি ফর্ম্যাটটির সাথে মেলানোর জন্য সূচিপত্রের মান পেতে পারি না।
obj.map = function() {
for(var i = 0; i < inputs.length; i++){
if(this._id.equals(inputs[i])) {
var order = i;
}
}
emit(order, {doc: this});
};
আপনি $ বা ধারা দিয়ে অর্ডার গ্যারান্টি দিতে পারেন।
$or: [ _ids.map(_id => ({_id}))]পরিবর্তে ব্যবহার করুন।
$orকার্যসংক্রান্ত কাজ করেননি v2.6 যেহেতু ।
মঙ্গো থেকে ফলাফল পুনরুদ্ধার করার পরে এটি একটি কোড সমাধান। সূচক সঞ্চয় করতে মানচিত্র ব্যবহার করা এবং তারপরে মানগুলি অদলবদল করা।
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++
}
}
}