1684566000
Есть два способа вычесть элементы из списка, используя другой список, в зависимости от того, есть ли в вашем списке повторяющиеся значения или нет.
Если в вашем списке есть повторяющиеся значения, вы можете использовать понимание списка с условным ifоператором
Если в вашем списке нет повторяющихся значений, вы можете преобразовать списки в наборы, вычесть элементы и преобразовать результат в список.
Этот учебник покажет вам, как использовать оба метода на практике.
Чтобы вычесть элементы из одного списка, используя другой список, вы можете использовать понимание списка и условный ifоператор.
Например, предположим, что вы хотите вычесть элементы из list_1использования list_2, как показано ниже:
list_1 = [1, 2, 3, 3, 5, 6, 7, 7, 9]
list_2 = [2, 3, 9]
# subtract elements from list_1 using list_2
result = [x for x in list_1 if x not in list_2]
print(result)
Выход:
[1, 5, 6, 7, 7]
Здесь успешно вычитаются элементы 2, 3 и 9 list_1.
Этот метод рекомендуется при наличии повторяющихся значений в исходном списке.
Объект setв Python может вычитать элементы из набора только с помощью -оператора минус.
Если в вашем списке нет повторяющихся значений, вы можете преобразовать список следующим образом:
list_1 = [1, 2, 3, 3, 5, 6, 7, 7, 9]
list_2 = [2, 3, 9]
# subtract elements as set objects
result = set(list_1) - set(list_2)
# convert result back to list
result = list(result)
print(result)
Выход:
[1, 5, 6, 7]
Обратите внимание, что повторяющиеся значения удаляются при преобразовании списка в набор.
Это связано с тем, что набор не может содержать повторяющиеся значения в Python.
В этом руководстве показано два самых простых способа вычитания элементов списка с помощью другого списка в Python.
Используйте понимание списка, когда у вас есть повторяющиеся значения, или используйте set()функцию для преобразования объекта и вычитания с помощью -оператора минус.
Я надеюсь, что это руководство поможет. До встречи на других уроках!
Оригинальный источник статьи: https://sebhastian.com/
1684565775
有两种方法可以使用另一个列表从列表中减去元素,具体取决于您的列表是否具有重复值。
if如果您的列表有重复值,那么您可以使用带有条件语句的列表理解
如果您的列表没有重复值,您可以将列表转换为集合,减去元素,并将结果转换为列表。
本教程将向您展示如何在实践中使用这两种方法。
要使用另一个列表从一个列表中减去元素,您可以使用列表理解和条件if语句。
例如,假设您要从list_1using中减去元素list_2,如下所示:
list_1 = [1, 2, 3, 3, 5, 6, 7, 7, 9]
list_2 = [2, 3, 9]
# subtract elements from list_1 using list_2
result = [x for x in list_1 if x not in list_2]
print(result)
输出:
[1, 5, 6, 7, 7]
此处,元素2、3、9减法成功list_1。
当您在原始列表中有重复值时,建议使用此方法。
Python 中的对象set仅使用减号运算符就可以从集合中减去元素-。
如果您的列表没有重复值,那么您可以将列表转换为如下设置:
list_1 = [1, 2, 3, 3, 5, 6, 7, 7, 9]
list_2 = [2, 3, 9]
# subtract elements as set objects
result = set(list_1) - set(list_2)
# convert result back to list
result = list(result)
print(result)
输出:
[1, 5, 6, 7]
请注意,将列表转换为集合时会删除重复值。
这是因为在 Python 中集合不能包含重复值。
本教程向您展示了在 Python 中使用另一个列表减去一个列表元素的两种最简单的方法。
当您有重复值时使用列表理解,或使用函数set()转换对象并使用减号-运算符减去。
我希望本教程有所帮助。在其他教程中见!
原始文章来源:https: //sebhastian.com/
1684558155
There are two ways you can subtract elements from a list using another list, depending on whether your list has duplicate values or not.
If your list has duplicate values, then you can use a list comprehension with a conditional if
statement
If your list has no duplicate values, you can transform the lists into sets, subtract the elements, and convert the result into a list.
This tutorial will show you how to use both methods in practice.
To subtract elements from one list using another list, you can use a list comprehension and a conditional if
statement.
For example, suppose you want to subtract elements from list_1
using list_2
as shown below:
list_1 = [1, 2, 3, 3, 5, 6, 7, 7, 9]
list_2 = [2, 3, 9]
# subtract elements from list_1 using list_2
result = [x for x in list_1 if x not in list_2]
print(result)
Output:
[1, 5, 6, 7, 7]
Here, the elements 2, 3, and 9 are subtracted from list_1
successfully.
This method is recommended when you have duplicate values in the original list.
The set
object in Python is able to subtract elements from a set by only using the minus -
operator.
If your list has no duplicate values, then you can convert the list to set as follows:
list_1 = [1, 2, 3, 3, 5, 6, 7, 7, 9]
list_2 = [2, 3, 9]
# subtract elements as set objects
result = set(list_1) - set(list_2)
# convert result back to list
result = list(result)
print(result)
Output:
[1, 5, 6, 7]
Notice that duplicate values are removed when you convert a list to a set.
This is because a set can’t contain duplicate values in Python.
This tutorial has shown you two easiest ways to subtract a list elements using another list in Python.
Use a list comprehension when you have duplicate values, or use the set()
function to convert the object and subtract using minus -
operator.
I hope this tutorial helps. See you in other tutorials!
Original article source at: https://sebhastian.com/
1673450520
Follow the steps mentioned below to migrate/copy a list from one site collection to another.
Export the list
Export list to another site collection
Uploading the list to a new site collection.
Problem: "Save List as Template" is missing in SharePoint Online modern sites.
Root Cause
"Custom script" feature is disabled!
Solution
Enable Custom Scripting at SharePoint Admin Center and Site Collection Levels.
To allow custom script in SharePoint Online, follow these steps:
Click on "OK" to save your changes.
This enables custom script in SharePoint Online. However, this change may take up to 24 Hours to reflect.
Original article source at: https://www.c-sharpcorner.com/
1665474900
Yet another second editor in RStudio.
The Monaco editor is the code editor which powers 'VS Code'. It is particularly well developed for JavaScript. In addition to the built-in features of the Monaco editor, the widget allows to prettify multiple languages, to view the HTML rendering of Markdown code, and to view and resize SVG images.
With the help of htmltools::browsable
, one can open two Monaco editors in the RStudio viewer pane:
The Monaco editor has many options. If you would like some of them to be available in the monaco
package, please fill an issue.
As any HTML widget, the Monaco editor widget can be used in Shiny apps:
This app uses the sass
package to compile some SCSS code to CSS code. It is one of the examples provided in the monaco
package.
monaco
widget but using the Shiny app locks RStudio.Author: stla
Source Code: https://github.com/stla/monaco
License: View license
1665179520
Yet another implement of skiplist in nodejs
Install
npm install jumplist
Examples
var JumpList = require('jumplist');
var list = new JumpList();
list.set('a', 5);
list.set('b', 6);
list.set('c', 8);
list.set('d', 9);
list.get('b');
>>> 6
list.remove('a');
list.get('a');
>>> undefined
list.range('c', 'e', function(key, value) {
console.info('=', key, value);
});
>> = c 8
>> = d 9
list.getAt(0);
>> {key: 'b', value: 6}
list.getAt(2);
>> {key: 'd', value: 9}
Author: Superisaac
Source Code: https://github.com/superisaac/node-jumplist
License: Unlicense license
1653737280
WHAT IS METEORIS?
Meteoris is a Realtime MVC + Modular Javascript Framework based on Meteor 1.2.0. This is the latest version of Meteoris out there. In this version, Meteoris still doesn't have a code generator. If you prefer using the old version of meteoris, please use this version https://github.com/radiegtya/meteoris-v1.
QUICKSTART
#install meteor
curl https://install.meteor.com/ | sh
#create new meteor project
meteor create my-meteoris-app
#the main module
meteor add meteoris:core
#another important module
meteor add meteoris:theme-admin
meteor add meteoris:user
meteor add meteoris:role
#remove meteor unused package
meteor remove insecure
meteor remove autopublish
We can easily hook navbar and sidebar to customize our own sidebar and navbar although we are using meteoris:admin-theme template. The content of each template is using navbar and sidebar Admin LTE style. Make sure you are using correct theme name "meteoris_themeAdmin_hookNavbar" for sidebar, and "meteoris_themeAdmin_hookSidebar" for navbar.
<template name="meteoris_themeAdmin_hookNavbar">
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
{{#if currentUser}}
<!-- User Account: style can be found in dropdown.less -->
<li class="dropdown user user-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<img src="/images/user.png" class="user-image" alt="User Image">
<span class="hidden-xs">{{currentUser.profile.name}}</span>
</a>
<ul class="dropdown-menu">
<!-- User image -->
<li class="user-header">
<img src="/images/user.png" class="img-circle" alt="User Image">
<p>
{{currentUser.profile.name}}
</p>
</li>
<!-- Menu Footer-->
<li class="user-footer">
<div class="pull-left">
<a href="#" class="btn btn-default btn-flat">Profile</a>
</div>
<div class="pull-right">
<a href="#" id="btnLogout" class="btn btn-default btn-flat">Logout</a>
</div>
</li>
</ul>
</li>
{{else}}
<li>
<a href="/meteoris/user/login">Login</a>
</li>
{{/if}}
</ul>
</div>
</template>
"at root/client/hook/navbar.html"
var ctrl = new Meteoris.UserController();
Template.meteoris_themeAdmin_hookNavbar.events = {
'click #btnLogout': function(){
ctrl.logout();
}
};
"at root/client/hook/navbar.js"
<template name="meteoris_themeAdmin_hookSidebar">
<!-- Left side column. contains the logo and sidebar -->
<aside class="main-sidebar">
<!-- sidebar: style can be found in sidebar.less -->
<section class="sidebar">
{{#if currentUser}}
<!-- Sidebar user panel -->
<div class="user-panel">
<div class="pull-left image">
<img src="/images/user.png" class="img-circle" alt="User Image">
</div>
<div class="pull-left info">
<p>{{currentUser.profile.name}}</p>
<a href="#"><i class="fa fa-circle text-success"></i> Online</a>
</div>
</div>
{{/if}}
<!--search form-->
<form action="#" method="get" class="sidebar-form">
<div class="input-group">
<input type="text" name="q" class="form-control" placeholder="Search...">
<span class="input-group-btn">
<button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i></button>
</span>
</div>
</form>
<!--/.search form-->
<!-- sidebar menu: : style can be found in sidebar.less -->
<ul class="sidebar-menu">
<li class="header">MAIN NAVIGATION</li>
<li><a href="/"><i class="fa fa-home"></i> Home</a></li>
<!--Uncomment this if you want to hide this menu using the power of meteoris:role-->
<!--{{#if meteoris_roleUserIsInGroup "admin"}}-->
<li class="header">ADMIN AREA</li>
<li class="treeview">
<a href="#">
<i class="fa fa-gears"></i>
<i class="fa fa-angle-left pull-right"></i>
<span>Setting</span>
</a>
<ul class="treeview-menu">
<li><a href="/meteoris/theme-admin/setting"><i class="fa fa-laptop"></i> Theme Admin Setting</a></li>
<li><a href="/meteoris/user"><i class="fa fa-users"></i> Users Management</a></li>
<li><a href="/meteoris/user/settings"><i class="fa fa-user"></i> User Settings</a></li>
<li><a href="/meteoris/role"><i class="fa fa-flag-o"></i> Role Management</a></li>
</ul>
</li>
<!--{{/if}}-->
</ul>
</section>
<!-- /.sidebar -->
</aside>
</template>
"at root/client/hook/sidebar.html"
Meteoris use simple MVC or MVVM + Modular paradigm to structuring app. Please use this standard structure to achieve best result when using meteoris.
3.1. Folder Structure
root/
meteorusernameorgroup:module/
client/ # Client folder
views/ # Views for html/js files
lib/ # Both Access folder
collections/ # Collections folder
controllers/ # Controllers Folder
router.js # Router js file
server/ # Server folder
3.2. Router Meteoris using Kadira Flow Router to linking between pages. Because we are using modular technique, assume that we are using my meteor account called "radiegtya" and using module name called "site". So we should make folder under root folder called "radiegtya:site". To use modular router, simply follow this step:
/**
create group routes, so every router has prefix radiegtya
*/
var groupRoutes = FlowRouter.group({
prefix: '/radiegtya',
name: 'radiegtya',
});
/**
create the main router called site, and use BlazeLayout render "meteoris_themeAdminMain" from metoris:theme-admin package, and accessing template called "radiegtya_siteIndex"
*/
groupRoutes.route('/site', {
action: function() {
BlazeLayout.render('meteoris_themeAdminMain', {content: "radiegtya_siteIndex"});
},
});
localhost:3000/radiegtya/site
3.3. Creating Controller for Site Controller actually just a method to be called inside your template js, and this will make your code more modular and readable.
/*
create a namespace called Radiegtya.SiteController
*/
Namespace('Radiegtya.SiteController');
/**
Create controller which extends Meteoris Controller
*/
Radiegtya.SiteController = Meteoris.Controller.extend({
constructor : function() {
// set default counter at constructor
Session.setDefault('counter', 0);
},
/* passing data to index helpers template */
index: function() {
//return some value, to be passed on index.js
return {
counter: this.getCounter(),
myName: "Ega Radiegtya",
myHobby: "Drinking Coffee"
};
},
getCounter: function(){
return Session.get("counter");
},
setCounter: function(counter){
Session.set('counter', this.getCounter() + 1);
}
});
3.4. Creating Views Page for Site
<template name="radiegtya_siteIndex">
<div class="content">
<div class="box">
<div class="box-body">
<button>Click Me</button>
<p>
You've pressed the button {{counter}} times.
</p>
</div>
</div>
</div>
</template>
because we are installing meteoris:theme-admin, you can use adminLTE styling and html inside your views html file. We are using meteor example to make You more familiar with the code.
var ctrl = new Radiegtya.SiteController();
/**
In the template helper section we are using index() method to get object return value from controller. It's because index was the action and also the file name suffix. This structure will make You easier to get jobs done, when your team getting bigger and the code getting bigger.
*/
Template.radiegtya_siteIndex.helpers({
myName: function () {
return ctrl.index().myName;
},
myHobby: function () {
return ctrl.index().myHobby;
},
counter: function () {
return ctrl.index().counter;
}
});
/**
in the template events, we don't need to use index() method to call any action. Because it just simply method calling through controller.
*/
Template.radiegtya_siteIndex.events({
'click button': function () {
//increment the counter when button is clicked
ctrl.setCounter();
}
});
Now finally access this route to check your apps.
localhost:3000/radiegtya/site
Awesome! We are successfully creating our simple app in MVC and Modular way with very easy setup. Ofc with amazing template which is reusable. You can also use this code to create a meteor package easily.
3.5. Creating Collection You can use aldeed:collection2, aldeed:simple-schema, and dburles:collection-helpers in our Meteoris collection. Future explanation will be comming soon. ======== COMING SOON =========
3.6. Creating Server You can use reywood:publish-composite here. Future explanation coming soon. ======== COMING SOON =========
3.7. Using Meteoris Plugin For now You can refer to the below this Quick Start article.
====================================================================================
#1. INSTALLATION
meteor add meteoris:core
it will also installing it's dependencies, which are:
Meteoris Package to show Flash/Toast Error/Success in your bottom right screen.
how to use in your js file:
//set flash message example
Meteoris.Flash.set('success', 'Data Successfully added');
Meteoris.Flash.set('danger', 'Data Failed to be added');
how to use in your html file:
<!-- Simply place this code on your html view anywhere -->
{{> meteoris_flash}}
Meteoris package to validate form easily. This Meteoris.FormValidation extension depends on collection2 and simpleschema:
AccountType = new Mongo.Collection("accountType");
var schemas = new SimpleSchema({
accountClassId: {
type: String,
label: "Kelas Akun",
},
});
AccountType.attachSchema(schemas);
/* show error message on view */
error: function(field) {
return Meteoris.FormValidation.error(YourCollectionName, field);
},
<div class="form-group {{#if error 'name'}}has-error{{/if}}">
<label for="name" class="control-label">Kelas Akun *</label>
<input type="text" id="name" value="{{name}}" placeholder="Kelas Akun" class="form-control" autofocus="true">
<span class="help-block">{{error "name"}}</span>
</div>
{{meteoris_formatter 'the function name' firstParam secondParam}}
- date (date)
- dateTime (date)
- elapsedTime (date)
- currency (value)
- combodate (date)
- combodateEmpty (date)
{{meteoris_formatter 'date' getCurrDate}}
Template.someTheme.helpers({
getCurrDate: function(){
return new Date();
}
});
<th id="btnSortName" class="{{meteoris_gridViewSortClass 'name'}}">Name</th>
Template.accountTypeIndex.events = {
/* sorting by parameter */
'click #btnSortName': function(e) {
Meteoris.GridView.sort('name');
},
}
#2. Install Meteoris Theme Admin (Not Required But It will better to be installed)
This current version of meteoris only have 1 theme which is called meteoris:theme-admin. This theme using popular Admin LTE for it's UI, Click here for more info about Admin LTE.
To install this theme, simply add meteor package:
meteor add meteoris:theme-admin
a. In your app client folder, create hook folder and inside it, add this template code. b. You can change everything such as loggedin user, global search, and menus inside the template as you wish
<!-- In your app client folder, create hook folder and inside it, add this template code. -->
<!-- You can change everything such as loggedin user, global search, and menus inside the template as you wish -->
<template name="meteoris_themeAdmin_hookSidebar">
<!-- Left side column. contains the logo and sidebar -->
<aside class="main-sidebar">
<!-- sidebar: style can be found in sidebar.less -->
<section class="sidebar">
{{#if currentUser}}
<!-- Sidebar user panel -->
<div class="user-panel">
<div class="pull-left image">
<img src="/images/user.png" class="img-circle" alt="User Image">
</div>
<div class="pull-left info">
<p>{{currentUser.profile.name}}</p>
<a href="#"><i class="fa fa-circle text-success"></i> Online</a>
</div>
</div>
{{/if}}
<!--search form-->
<form action="#" method="get" class="sidebar-form">
<div class="input-group">
<input type="text" name="q" class="form-control" placeholder="Search...">
<span class="input-group-btn">
<button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i></button>
</span>
</div>
</form>
<!--/.search form-->
<!-- sidebar menu: : style can be found in sidebar.less -->
<ul class="sidebar-menu">
<li class="header">MAIN NAVIGATION</li>
<li><a href="/"><i class="fa fa-home"></i> Home</a></li>
<!--Uncomment this if you want to hide this menu using the power of meteoris:role-->
<!--{{#if meteoris_roleUserIsInGroup "admin"}}-->
<li class="header">ADMIN AREA</li>
<li class="treeview">
<a href="#">
<i class="fa fa-gears"></i>
<i class="fa fa-angle-left pull-right"></i>
<span>Setting</span>
</a>
<ul class="treeview-menu">
<li><a href="/meteoris/theme-admin/setting"><i class="fa fa-laptop"></i> Theme Admin Setting</a></li>
<li><a href="/meteoris/user"><i class="fa fa-users"></i> Users Management</a></li>
<li><a href="/meteoris/user/settings"><i class="fa fa-user"></i> User Settings</a></li>
<li><a href="/meteoris/role"><i class="fa fa-flag-o"></i> Role Management</a></li>
</ul>
</li>
<!--{{/if}}-->
</ul>
</section>
<!-- /.sidebar -->
</aside>
</template>
<template name="meteoris_themeAdmin_hookNavbar">
<div class="navbar-custom-menu">
<ul class="nav navbar-nav">
{{#if currentUser}}
<!-- User Account: style can be found in dropdown.less -->
<li class="dropdown user user-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<img src="/images/user.png" class="user-image" alt="User Image">
<span class="hidden-xs">{{currentUser.profile.name}}</span>
</a>
<ul class="dropdown-menu">
<!-- User image -->
<li class="user-header">
<img src="/images/user.png" class="img-circle" alt="User Image">
<p>
{{currentUser.profile.name}}
</p>
</li>
<!-- Menu Footer-->
<li class="user-footer">
<div class="pull-left">
<a href="#" class="btn btn-default btn-flat">Profile</a>
</div>
<div class="pull-right">
<a href="#" id="btnLogout" class="btn btn-default btn-flat">Logout</a>
</div>
</li>
</ul>
</li>
{{else}}
<li>
<a href="/meteoris/user/login">Login</a>
</li>
{{/if}}
</ul>
</div>
</template>
c. add js file according to the template to get some event, and helper
var ctrl = new Meteoris.UserController();
Template.meteoris_themeAdmin_hookNavbar.events = {
'click #btnLogout': function(){
ctrl.logout();
}
};
#3. Meteoris User (Not Required but it will be better to be installed)
'/meteoris/user', #to manage user as admin
'/meteoris/user/login', #to logged in the user and '/meteoris/user/register', #to registering user
'/meteoris/user/profile' #to updating current logged in user profile
'/meteoris/user/settings', #to setting user oauth account
#4. Install Meteoris Role (Not Required but it will be better to be installed)
//you can use this code on collection-allow or on server
Meteoris.Role.userIsInRole(collection, action);
//example on collection:
MyCollection.allow({
insert: function(userId, doc) {
return Meteoris.Role.userIsInRole("my-collection", Meteoris.Role.POST);
},
update: function(userId, doc) {
return Meteoris.Role.userIsInRole("my-collection", Meteoris.Role.PUT);
},
remove: function(userId, doc) {
return Meteoris.Role.userIsInRole("my-collection", Meteoris.Role.DELETE);
},
});
//example on router
var roleRoutes = FlowRouter.group({
prefix: '/meteoris/role',
name: 'meteoris_role',
triggersEnter: [authenticating]
});
/* router level validation, only allow user with group "admin" to access this page */
function authenticating() {
if (!Meteoris.Role.userIsInRole("my-collection", Meteoris.Role.GET_ALL)){
Meteoris.Flash.set("danger", "403 Unauthenticated");
FlowRouter.go("/");
}
}
//you can use this code on collection-allow or on server
Meteoris.Role.userIsInGroup(groupName);
//example on collection:
MyCollection.allow({
insert: function(userId, doc) {
return Meteoris.Role.userIsInGroup("admin");
},
update: function(userId, doc) {
return Meteoris.Role.userIsInGroup("admin");
},
remove: function(userId, doc) {
return Meteoris.Role.userIsInGroup("admin");
},
});
var roleRoutes = FlowRouter.group({
prefix: '/meteoris/role',
name: 'meteoris_role',
triggersEnter: [authenticating]
});
/* router level validation, only allow user with group "admin" to access this page */
function authenticating() {
if (!Meteoris.Role.userIsInGroup("user")){
Meteoris.Flash.set("danger", "403 Unauthenticated");
FlowRouter.go("/");
}
}
//you can use this code on client template html
{{#if meteoris_roleUserIsInRole "collectionName" "actionName"}}
<!-- Your logic here -->
{{/if}}
//example on client template html:
{{#if meteoris_roleUserIsInRole "my-collection" "GET_ALL"}}
<li><a href="/my-collection"><i class="fa fa-flag-o"></i> My Collection Menu</a></li>
{{/if}}
//you can use this code on client template html
{{#if meteoris_roleUserIsInGroup "groupName"}}
<!-- Your logic here -->
{{/if}}
//example on client template html:
{{#if meteoris_roleUserIsInGroup "admin"}}
<li><a href="/my-collection"><i class="fa fa-flag-o"></i> My Collection Menu</a></li>
{{/if}}
Author: Meteoris
Source Code: https://github.com/meteoris/meteoris
License:
1651910400
Mixer is a MySQL proxy powered by Go which aims to supply a simple solution for MySQL sharding.
COM_STMT_PREPARE
, COM_STMT_EXECUTE
, etc.show databases
, etc.select @@version
, etc.cd $WORKSPACE
git clone git@github.com:siddontang/mixer.git src/github.com/siddontang/mixer
cd src/github.com/siddontang/mixer
./bootstrap.sh
. ./dev.env
make
make test
A proxy is the bridge connecting clients and the real MySQL servers.
It acts as a MySQL server too, clients can communicate with it using the MySQL procotol.
Mixer uses nodes to represent the real remote MySQL servers. A node can have two MySQL servers:
rw_split
and slave are not set) will be executed here. All transactions will be executed here too.rw_split
is set, any select operations will be executed here. (can not set)Notice:
admin upnode
or admin downnode
commands to bring a specified MySQL server up or down.Schema likes MySQL database, if a client executes use db
command, db
must exist in the schema.
A schema contains one or more nodes. If a client use the specified schema, any command will be only routed to the node which belongs to the schema to be executed.
You must set some rules for a schema to let the mixer decide how to route SQL statements to different nodes to be executed.
Mixer uses table + key
to route. Duplicate rule for a table are not allowed.
When SQL needs to be routed, mixer does the following steps:
Rules have three types: default, hash and range.
A schema must have a default rule with only one node assigned.
For hash and range routing you can see the example below.
Mixer suplies admin
statement to administrate. The admin
format is admin func(arg, ...)
like select func(arg,...)
. Later we may add admin password for safe use.
Support admin functions now:
- admin upnode(node, serverype, addr);
- admin downnode(node, servertype);
- show proxy config;
#start mixer
mixer-proxy -config=/etc/mixer.conf
#another shell
mysql -uroot -h127.0.0.1 -P4000 -p -Dmixer
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 158
Server version: 5.6.19 Homebrew
mysql> use mixer;
Database changed
mysql> delete from mixer_test_conn;
Query OK, 3 rows affected (0.04 sec)
mysql> insert into mixer_test_conn (id, str) values (1, "a");
Query OK, 1 row affected (0.00 sec)
mysql> insert into mixer_test_conn (id, str) values (2, "b");
Query OK, 1 row affected (0.00 sec)
mysql> select id, str from mixer_test_conn;
+----+------+
| id | str |
+----+------+
| 1 | a |
| 2 | b |
+----+------+
schemas :
-
db : mixer
nodes: [node1, node2, node3]
rules:
default: node1
shard:
-
table: mixer_test_shard_hash
key: id
nodes: [node2, node3]
type: hash
hash algorithm: value % len(nodes)
table: mixer_test_shard_hash
Node: node2, node3
node2 mysql: 127.0.0.1:3307
node3 mysql: 127.0.0.1:3308
mixer-proxy: 127.0.0.1:4000
proxy> mysql -uroot -h127.0.0.1 -P4000 -p -Dmixer
node2> mysql -uroot -h127.0.0.1 -P3307 -p -Dmixer
node3> mysql -uroot -h127.0.0.1 -P3307 -p -Dmixer
proxy> insert into mixer_test_shard_hash (id, str) values (0, "a");
node2> select str from mixer_test_shard_hash where id = 0;
+------+
| str |
+------+
| a |
+------+
proxy> insert into mixer_test_shard_hash (id, str) values (1, "b");
node3> select str from mixer_test_shard_hash where id = 1;
+------+
| str |
+------+
| b |
+------+
proxy> select str from mixer_test_shard_hash where id in (0, 1);
+------+
| str |
+------+
| a |
| b |
+------+
proxy> select str from mixer_test_shard_hash where id = 0 or id = 1;
+------+
| str |
+------+
| a |
| b |
+------+
proxy> select str from mixer_test_shard_hash where id = 0 and id = 1;
Empty set
schemas :
-
db : mixer
nodes: [node1, node2, node3]
rules:
default: node1
shard:
-
table: mixer_test_shard_range
key: id
nodes: [node2, node3]
range: -10000-
type: range
range algorithm: node key start <= value < node key stop
table: mixer_test_shard_range
Node: node2, node3
node2 range: (-inf, 10000)
node3 range: [10000, +inf)
node2 mysql: 127.0.0.1:3307
node3 mysql: 127.0.0.1:3308
mixer-proxy: 127.0.0.1:4000
proxy> mysql -uroot -h127.0.0.1 -P4000 -p -Dmixer
node2> mysql -uroot -h127.0.0.1 -P3307 -p -Dmixer
node3> mysql -uroot -h127.0.0.1 -P3307 -p -Dmixer
proxy> insert into mixer_test_shard_range (id, str) values (0, "a");
node2> select str from mixer_test_shard_range where id = 0;
+------+
| str |
+------+
| a |
+------+
proxy> insert into mixer_test_shard_range (id, str) values (10000, "b");
node3> select str from mixer_test_shard_range where id = 10000;
+------+
| str |
+------+
| b |
+------+
proxy> select str from mixer_test_shard_range where id in (0, 10000);
+------+
| str |
+------+
| a |
| b |
+------+
proxy> select str from mixer_test_shard_range where id = 0 or id = 10000;
+------+
| str |
+------+
| a |
| b |
+------+
proxy> select str from mixer_test_shard_range where id = 0 and id = 10000;
Empty set
proxy> select str from mixer_test_shard_range where id > 100;
+------+
| str |
+------+
| b |
+------+
proxy> select str from mixer_test_shard_range where id < 100;
+------+
| str |
+------+
| a |
+------+
proxy> select str from mixer_test_shard_range where id >=0 and id < 100000;
+------+
| str |
+------+
| a |
| b |
+------+
Join not supported, later only cross sharding not supported.
Subselects not supported, later only cross sharding not supported.
Cross sharding "group by" will not work ok only except the "group by" key is the routing key
Cross sharding "order by" only takes effect when the "order by" key exists as a select expression field
select id from t1 order by id
is ok.
select str from t1 order by id
is not ok, mixer does not known how to sort because it can not find proper data to compare with id
Limit should be used with "order by", otherwise you may receive incorrect results
Vitess is very awesome, and I use some of its code like sqlparser. Why not use vitess directly? Maybe below:
Author: siddontang
Source Code: https://github.com/siddontang/mixer
License: View license